{
  "$defs": {
    "flexway.v1.operation": {
      "additionalProperties": false,
      "description": "gRPC method option (`option (flexway.v1.operation) = { ... };` in the `.proto`): what the gateway needs to know about a method, the counterpart of an OpenAPI operation's `x-flexway-*` extensions. Read from the descriptor set with its imports; every field is optional, the host's default applies otherwise.",
      "properties": {
        "ai": {
          "additionalProperties": false,
          "description": "Makes the method a specialised model metered by the inference plane (the counterpart of `x-flexway-ai`): counted into the tenant's euro budget, per call or per byte, without reading the body. Requires an `ai` section and a `kind: grpc` backend of `ai.backends` naming the method's upstream.",
          "properties": {
            "capability": {
              "default": "model",
              "description": "Capability the series are labelled with: `model` (default), `vision`, `embeddings` or `chat`.",
              "enum": [
                "model",
                "vision",
                "embeddings",
                "chat"
              ],
              "type": "string",
              "x-flexway-description": {
                "en": "Capability the series are labelled with: `model` (default), `vision`, `embeddings` or `chat`.",
                "fr": "Capacité dont les séries sont étiquetées : `model` (défaut), `vision`, `embeddings` ou `chat`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.5.0"
            },
            "price_per_1k": {
              "description": "Price of a thousand units, in euros; zero or more (`0` is a price).",
              "minimum": 0,
              "type": "number",
              "x-flexway-description": {
                "en": "Price of a thousand units, in euros; zero or more (`0` is a price).",
                "fr": "Prix de mille unités, en euros ; positif ou nul (`0` est un prix)."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.5.0"
            },
            "unit": {
              "default": "call",
              "description": "Unit counted: `call` (default), one unit per call; `byte`, one per byte of the request and of the answer.",
              "enum": [
                "call",
                "byte"
              ],
              "type": "string",
              "x-flexway-description": {
                "en": "Unit counted: `call` (default), one unit per call; `byte`, one per byte of the request and of the answer.",
                "fr": "Unité comptée : `call` (défaut), une unité par appel ; `byte`, une par octet de la requête et de la réponse."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.5.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Makes the method a specialised model metered by the inference plane (the counterpart of `x-flexway-ai`): counted into the tenant's euro budget, per call or per byte, without reading the body. Requires an `ai` section and a `kind: grpc` backend of `ai.backends` naming the method's upstream.",
            "fr": "Fait de la méthode un modèle spécialisé mesuré par le plan d'inférence (équivalent de `x-flexway-ai`) : compté dans le budget en euros du tenant, à l'appel ou à l'octet, sans lire le corps. Exige une section `ai` et un backend `kind: grpc` de `ai.backends` qui nomme l'amont de la méthode."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        },
        "metadata": {
          "description": "Request metadata allowed through to the upstream, beside gRPC's own: closed by default, metadata not listed does not pass.",
          "items": {
            "type": "string"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "Request metadata allowed through to the upstream, beside gRPC's own: closed by default, metadata not listed does not pass.",
            "fr": "Métadonnées de requête autorisées vers l'amont, en plus de celles de gRPC : fermé par défaut, une métadonnée non listée ne passe pas."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.1.0"
        },
        "owner": {
          "additionalProperties": false,
          "description": "Team that answers for the method (the counterpart of `x-flexway-owner`): shown in the console's catalogue, never read on the request path.",
          "properties": {
            "contact": {
              "description": "How to reach the team - a channel, a list, a page; 128 characters at most. Never a person: every reader of the catalogue sees it.",
              "maxLength": 128,
              "type": "string",
              "x-flexway-description": {
                "en": "How to reach the team - a channel, a list, a page; 128 characters at most. Never a person: every reader of the catalogue sees it.",
                "fr": "Comment joindre l'équipe - un canal, une liste, une page ; 128 caractères au plus. Jamais une personne : tout lecteur du catalogue le voit."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.2.0"
            },
            "team": {
              "description": "Team name, required as soon as `owner` is written; not blank, 128 characters at most.",
              "maxLength": 128,
              "minLength": 1,
              "type": "string",
              "x-flexway-description": {
                "en": "Team name, required as soon as `owner` is written; not blank, 128 characters at most.",
                "fr": "Nom de l'équipe, obligatoire dès que `owner` est écrit ; non vide, 128 caractères au plus."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.2.0"
            }
          },
          "required": [
            "team"
          ],
          "type": "object",
          "x-flexway-description": {
            "en": "Team that answers for the method (the counterpart of `x-flexway-owner`): shown in the console's catalogue, never read on the request path.",
            "fr": "Équipe qui répond de la méthode (équivalent de `x-flexway-owner`) : affichée au catalogue de la console, jamais lue sur le chemin de la requête."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "policies": {
          "description": "The method's own level of the policy chain (the counterpart of `x-flexway-policies`): names from `policies.definitions`; `!name` removes a policy a broader level brought.",
          "items": {
            "type": "string"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "The method's own level of the policy chain (the counterpart of `x-flexway-policies`): names from `policies.definitions`; `!name` removes a policy a broader level brought.",
            "fr": "Niveau propre de la méthode dans la chaîne de politiques (équivalent de `x-flexway-policies`) : noms de `policies.definitions` ; `!nom` retire une politique apportée par un niveau plus large."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.1.0"
        },
        "priority": {
          "default": "normal",
          "description": "Shedding priority: `critical` (never shed), `normal` (default) or `sheddable` (shed first).",
          "enum": [
            "critical",
            "normal",
            "sheddable"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "Shedding priority: `critical` (never shed), `normal` (default) or `sheddable` (shed first).",
            "fr": "Priorité de délestage : `critical` (jamais délestée), `normal` (défaut) ou `sheddable` (délestée en premier)."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.1.0"
        },
        "rate_class": {
          "description": "Rate-limit class of the method (the counterpart of `x-flexway-rate-class`), defined by the chain's `rate-limit` policy. Empty: `read` for a method without side effects or bound to `GET`, `write` otherwise.",
          "type": "string",
          "x-flexway-description": {
            "en": "Rate-limit class of the method (the counterpart of `x-flexway-rate-class`), defined by the chain's `rate-limit` policy. Empty: `read` for a method without side effects or bound to `GET`, `write` otherwise.",
            "fr": "Classe de débit de la méthode (équivalent de `x-flexway-rate-class`), définie par la politique `rate-limit` de la chaîne. Vide : `read` pour une méthode sans effet de bord ou liée en `GET`, `write` sinon."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.1.0"
        },
        "security": {
          "description": "Access alternatives, any one of which suffices - like an OpenAPI `security` list. Empty: no identity required.",
          "items": {
            "additionalProperties": false,
            "properties": {
              "anonymous": {
                "description": "The empty alternative: no identity required. Takes precedence over the alternative's other fields.",
                "type": "boolean",
                "x-flexway-description": {
                  "en": "The empty alternative: no identity required. Takes precedence over the alternative's other fields.",
                  "fr": "Alternative vide : aucune identité exigée. Prime sur les autres champs de l'alternative."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.1.0"
              },
              "api_key": {
                "description": "An API key bound to the method (`Authorization: ApiKey ...`) satisfies this alternative; scopes and roles are ignored there.",
                "type": "boolean",
                "x-flexway-description": {
                  "en": "An API key bound to the method (`Authorization: ApiKey ...`) satisfies this alternative; scopes and roles are ignored there.",
                  "fr": "Une clé d'API liée à la méthode (`Authorization: ApiKey ...`) satisfait cette alternative ; portées et rôles y sont ignorés."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.1.0"
              },
              "mutual_tls": {
                "description": "A client certificate bound to the method satisfies this alternative; scopes and roles are ignored there.",
                "type": "boolean",
                "x-flexway-description": {
                  "en": "A client certificate bound to the method satisfies this alternative; scopes and roles are ignored there.",
                  "fr": "Un certificat client lié à la méthode satisfait cette alternative ; portées et rôles y sont ignorés."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.1.0"
              },
              "roles": {
                "description": "Roles a token must all carry, read from its issuer's `roles_claim`.",
                "items": {
                  "type": "string"
                },
                "type": "array",
                "x-flexway-description": {
                  "en": "Roles a token must all carry, read from its issuer's `roles_claim`.",
                  "fr": "Rôles qu'un jeton doit tous porter, lus par la claim `roles_claim` de son émetteur."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.1.0"
              },
              "scopes": {
                "description": "Scopes a token must all carry.",
                "items": {
                  "type": "string"
                },
                "type": "array",
                "x-flexway-description": {
                  "en": "Scopes a token must all carry.",
                  "fr": "Portées qu'un jeton doit toutes porter."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.1.0"
              }
            },
            "type": "object"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "Access alternatives, any one of which suffices - like an OpenAPI `security` list. Empty: no identity required.",
            "fr": "Alternatives d'accès, dont une seule suffit - comme la liste `security` d'OpenAPI. Vide : aucune identité exigée."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.1.0"
        },
        "sunset": {
          "description": "Date the method is withdrawn, `YYYY-MM-DD` (the counterpart of `x-flexway-sunset`). Only on a method marked `option deprecated = true;`: refused at load otherwise.",
          "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
          "type": "string",
          "x-flexway-description": {
            "en": "Date the method is withdrawn, `YYYY-MM-DD` (the counterpart of `x-flexway-sunset`). Only on a method marked `option deprecated = true;`: refused at load otherwise.",
            "fr": "Date de retrait de la méthode, `AAAA-MM-JJ` (équivalent de `x-flexway-sunset`). Seulement sur une méthode marquée `option deprecated = true;` : refusée au chargement sinon."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "timeout": {
          "description": "Total budget of one call, a positive duration (`3s`); empty: the upstream's.",
          "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
          "type": "string",
          "x-flexway-description": {
            "en": "Total budget of one call, a positive duration (`3s`); empty: the upstream's.",
            "fr": "Budget total d'un appel, durée positive (`3s`) ; vide : celui de l'amont."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.1.0"
        },
        "upstream": {
          "description": "Upstream that serves the method, declared in `upstreams`; empty: the host's default upstream.",
          "type": "string",
          "x-flexway-description": {
            "en": "Upstream that serves the method, declared in `upstreams`; empty: the host's default upstream.",
            "fr": "Amont qui sert la méthode, déclaré dans `upstreams` ; vide : l'amont par défaut de l'hôte."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.1.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "gRPC method option (`option (flexway.v1.operation) = { ... };` in the `.proto`): what the gateway needs to know about a method, the counterpart of an OpenAPI operation's `x-flexway-*` extensions. Read from the descriptor set with its imports; every field is optional, the host's default applies otherwise.",
        "fr": "Option de méthode gRPC (`option (flexway.v1.operation) = { ... };` dans le `.proto`) : ce que la passerelle doit savoir d'une méthode, l'équivalent des extensions `x-flexway-*` d'une opération OpenAPI. Lue dans le jeu de descripteurs avec ses imports ; chaque champ est facultatif, l'hôte décide à défaut."
      },
      "x-flexway-places": [
        "grpc.method"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.1.0"
    },
    "x-flexway-a2a": {
      "additionalProperties": false,
      "description": "Governance block of an A2A agent, at the top level of its declared card (`contracts.a2a`), required; removed from the published card. Unknown keys are refused.",
      "properties": {
        "delegation": {
          "additionalProperties": false,
          "description": "Bounds of the agent chain for this agent `{ max_depth, max_age }`: requires `agents.delegation` and may only tighten it - a wider bound is refused.",
          "properties": {
            "max_age": {
              "description": "Maximum age since the person authenticated, a positive duration; never beyond `agents.delegation.max_age`.",
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Maximum age since the person authenticated, a positive duration; never beyond `agents.delegation.max_age`.",
                "fr": "Âge maximal depuis l'authentification de la personne, durée positive ; jamais au-delà de `agents.delegation.max_age`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.2.0"
            },
            "max_depth": {
              "description": "Maximum number of agents in the chain, an integer of 0 or more; never beyond `agents.delegation.max_depth`.",
              "minimum": 0,
              "type": "integer",
              "x-flexway-description": {
                "en": "Maximum number of agents in the chain, an integer of 0 or more; never beyond `agents.delegation.max_depth`.",
                "fr": "Nombre maximal d'agents dans la chaîne, entier positif ou nul ; jamais au-delà de `agents.delegation.max_depth`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.2.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Bounds of the agent chain for this agent `{ max_depth, max_age }`: requires `agents.delegation` and may only tighten it - a wider bound is refused.",
            "fr": "Bornes de la chaîne d'agents pour cet agent `{ max_depth, max_age }` : exige `agents.delegation` et ne peut que les resserrer - une borne plus large est refusée."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "max_streams": {
          "description": "Streams open at most per replica for this agent; required and greater than 0 when the card announces `capabilities.streaming`.",
          "minimum": 0,
          "type": "integer",
          "x-flexway-description": {
            "en": "Streams open at most per replica for this agent; required and greater than 0 when the card announces `capabilities.streaming`.",
            "fr": "Flux ouverts au plus par réplique pour cet agent ; obligatoire et supérieur à 0 si la carte annonce `capabilities.streaming`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "max_task_duration": {
          "description": "Maximum duration of a task followed as a stream, a positive duration (`10m`); required when the card announces `capabilities.streaming`.",
          "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
          "type": "string",
          "x-flexway-description": {
            "en": "Maximum duration of a task followed as a stream, a positive duration (`10m`); required when the card announces `capabilities.streaming`.",
            "fr": "Durée maximale d'une tâche suivie en flux, durée positive (`10m`) ; obligatoire si la carte annonce `capabilities.streaming`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "methods": {
          "additionalProperties": {
            "pattern": "^[a-z][a-z0-9_-]{0,31}$",
            "type": "string"
          },
          "description": "Rate class per A2A method (`SendMessage`, `GetTask`, `CancelTask`...), `^[a-z][a-z0-9_-]{0,31}$`. Default: `write` for sends, `CancelTask` and creating or deleting a push notification configuration, `free` for the rest.",
          "propertyNames": {
            "enum": [
              "SendMessage",
              "SendStreamingMessage",
              "GetTask",
              "ListTasks",
              "CancelTask",
              "SubscribeToTask",
              "CreateTaskPushNotificationConfig",
              "GetTaskPushNotificationConfig",
              "ListTaskPushNotificationConfigs",
              "DeleteTaskPushNotificationConfig",
              "GetExtendedAgentCard"
            ]
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Rate class per A2A method (`SendMessage`, `GetTask`, `CancelTask`...), `^[a-z][a-z0-9_-]{0,31}$`. Default: `write` for sends, `CancelTask` and creating or deleting a push notification configuration, `free` for the rest.",
            "fr": "Classe de débit par méthode A2A (`SendMessage`, `GetTask`, `CancelTask`...), `^[a-z][a-z0-9_-]{0,31}$`. Défaut : `write` pour les envois, `CancelTask` et la création ou suppression d'une configuration de notification, `free` pour le reste."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "signer": {
          "description": "Signer of the published card: not accepted yet, any value is refused.",
          "not": {},
          "type": "string",
          "x-flexway-description": {
            "en": "Signer of the published card: not accepted yet, any value is refused.",
            "fr": "Signataire de la carte publiée : pas encore accepté, toute valeur est refusée."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.10.0"
        },
        "upstream": {
          "description": "Upstream that serves the agent, declared in `upstreams` with `protocol: a2a` (hence `token_exchange`); required.",
          "type": "string",
          "x-flexway-description": {
            "en": "Upstream that serves the agent, declared in `upstreams` with `protocol: a2a` (hence `token_exchange`); required.",
            "fr": "Amont qui sert l'agent, déclaré dans `upstreams` avec `protocol: a2a` (et donc `token_exchange`) ; obligatoire."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "verify": {
          "description": "Verification of the upstream's card: `none` only, required.",
          "enum": [
            "none"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "Verification of the upstream's card: `none` only, required.",
            "fr": "Vérification de la carte de l'amont : `none` seulement, obligatoire."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        }
      },
      "required": [
        "upstream",
        "verify"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "Governance block of an A2A agent, at the top level of its declared card (`contracts.a2a`), required; removed from the published card. Unknown keys are refused.",
        "fr": "Bloc de gouvernance d'un agent A2A, au premier niveau de sa carte déclarée (`contracts.a2a`), obligatoire ; retiré de la carte publiée. Clés inconnues refusées."
      },
      "x-flexway-places": [
        "a2a.card"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.2.0"
    },
    "x-flexway-ai": {
      "additionalProperties": false,
      "description": "Name of the `ai` option of `flexway.v1.operation` on a gRPC method: the method is a metered model. Refused in an OpenAPI or AsyncAPI contract.",
      "properties": {
        "capability": {
          "default": "model",
          "description": "Capability of the series: `model` (default), `vision`, `embeddings` or `chat`.",
          "enum": [
            "model",
            "vision",
            "embeddings",
            "chat"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "Capability of the series: `model` (default), `vision`, `embeddings` or `chat`.",
            "fr": "Capacité des séries : `model` (défaut), `vision`, `embeddings` ou `chat`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        },
        "price_per_1k": {
          "description": "Price of a thousand units, in euros; zero or more.",
          "minimum": 0,
          "type": "number",
          "x-flexway-description": {
            "en": "Price of a thousand units, in euros; zero or more.",
            "fr": "Prix de mille unités, en euros ; positif ou nul."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        },
        "unit": {
          "default": "call",
          "description": "Unit counted: `call` (default) or `byte` (bytes of the request and of the answer).",
          "enum": [
            "call",
            "byte"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "Unit counted: `call` (default) or `byte` (bytes of the request and of the answer).",
            "fr": "Unité comptée : `call` (défaut) ou `byte` (octets de la requête et de la réponse)."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "Name of the `ai` option of `flexway.v1.operation` on a gRPC method: the method is a metered model. Refused in an OpenAPI or AsyncAPI contract.",
        "fr": "Nom de l'option `ai` de `flexway.v1.operation` sur une méthode gRPC : la méthode est un modèle mesuré. Refusée dans un contrat OpenAPI ou AsyncAPI."
      },
      "x-flexway-places": [
        "grpc.method"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.5.0"
    },
    "x-flexway-bind": {
      "description": "On an AsyncAPI channel parameter: binds the parameter to a fact of the verified identity, never read from the request - `tenant`, `subject`, `claim:<name>` (a name of 1 to 64 characters `[A-Za-z0-9_.-]`) or, on an `x-flexway-device` operation, `cert:<field>` of the device certificate - `cn`, `serial`, `fingerprint`, or with its index `ou[i]`, `o[i]`, `san.dns[i]`, `san.uri[i]`, `san.ip[i]`, `san.email[i]`. Required on every parameter of a channel in use, which must appear in the address.",
      "pattern": "^(tenant|subject|claim:[A-Za-z0-9_.-]{1,64}|cert:(cn|serial|fingerprint|(ou|o|san\\.dns|san\\.uri|san\\.ip|san\\.email)\\[[0-9]{1,2}\\]))$",
      "type": "string",
      "x-flexway-description": {
        "en": "On an AsyncAPI channel parameter: binds the parameter to a fact of the verified identity, never read from the request - `tenant`, `subject`, `claim:<name>` (a name of 1 to 64 characters `[A-Za-z0-9_.-]`) or, on an `x-flexway-device` operation, `cert:<field>` of the device certificate - `cn`, `serial`, `fingerprint`, or with its index `ou[i]`, `o[i]`, `san.dns[i]`, `san.uri[i]`, `san.ip[i]`, `san.email[i]`. Required on every parameter of a channel in use, which must appear in the address.",
        "fr": "Sur un paramètre de canal AsyncAPI : lie le paramètre à un fait de l'identité vérifiée, jamais lu de la requête - `tenant`, `subject`, `claim:<nom>` (nom de 1 à 64 caractères `[A-Za-z0-9_.-]`) ou, sur une opération `x-flexway-device`, `cert:<champ>` du certificat de l'appareil - `cn`, `serial`, `fingerprint`, ou avec son indice `ou[i]`, `o[i]`, `san.dns[i]`, `san.uri[i]`, `san.ip[i]`, `san.email[i]`. Obligatoire sur chaque paramètre d'un canal utilisé, qui doit figurer dans l'adresse."
      },
      "x-flexway-places": [
        "asyncapi.parameter"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.5.0"
    },
    "x-flexway-cache": {
      "additionalProperties": false,
      "description": "On an OpenAPI `GET` or `HEAD` operation: the operation's own response cache, `{ ttl, scope }`. Refused on a stream, a WebSocket, a gRPC method, an A2A operation, a broker door, and together with a `cache` policy named by `x-flexway-policies`.",
      "properties": {
        "scope": {
          "default": "public",
          "description": "`public` (default): shared, refused when the operation requires an identity; `subject`: keyed by tenant and subject, the only way an authenticated response is cached, refused on an operation without `security`.",
          "enum": [
            "public",
            "subject"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "`public` (default): shared, refused when the operation requires an identity; `subject`: keyed by tenant and subject, the only way an authenticated response is cached, refused on an operation without `security`.",
            "fr": "`public` (défaut) : partagé, refusé si l'opération exige une identité ; `subject` : clé tenant et sujet, la seule façon de cacher une réponse authentifiée, refusé sur une opération sans `security`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "ttl": {
          "description": "How long a response is kept, a positive duration (`30s`); required.",
          "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 (`30s`); required.",
            "fr": "Durée de conservation, durée positive (`30s`) ; obligatoire."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        }
      },
      "required": [
        "ttl"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "On an OpenAPI `GET` or `HEAD` operation: the operation's own response cache, `{ ttl, scope }`. Refused on a stream, a WebSocket, a gRPC method, an A2A operation, a broker door, and together with a `cache` policy named by `x-flexway-policies`.",
        "fr": "Sur une opération OpenAPI `GET` ou `HEAD` : cache de réponses propre à l'opération, `{ ttl, scope }`. Refusé sur un flux, un WebSocket, une méthode gRPC, une opération A2A, une porte de courtier, et avec une politique `cache` nommée par `x-flexway-policies`."
      },
      "x-flexway-places": [
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.2.0"
    },
    "x-flexway-delegation": {
      "additionalProperties": false,
      "description": "On an OpenAPI operation: tightens the agent chain bounds for it, `{ max_depth, max_age }`; never wider than `agents.delegation`, which applies otherwise.",
      "properties": {
        "max_age": {
          "description": "Maximum age since the person authenticated, a positive duration; absent: the configuration's bound.",
          "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
          "type": "string",
          "x-flexway-description": {
            "en": "Maximum age since the person authenticated, a positive duration; absent: the configuration's bound.",
            "fr": "Âge maximal depuis l'authentification de la personne, durée positive ; absent : la borne de la configuration."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.7.0"
        },
        "max_depth": {
          "description": "Maximum number of agents in the chain, an integer of 0 or more (`0` refuses any delegated token); absent: the configuration's bound.",
          "minimum": 0,
          "type": "integer",
          "x-flexway-description": {
            "en": "Maximum number of agents in the chain, an integer of 0 or more (`0` refuses any delegated token); absent: the configuration's bound.",
            "fr": "Nombre maximal d'agents dans la chaîne, entier positif ou nul (`0` refuse tout jeton délégué) ; absent : la borne de la configuration."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.7.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "On an OpenAPI operation: tightens the agent chain bounds for it, `{ max_depth, max_age }`; never wider than `agents.delegation`, which applies otherwise.",
        "fr": "Sur une opération OpenAPI : resserre pour elle les bornes de la chaîne d'agents, `{ max_depth, max_age }` ; jamais plus large que `agents.delegation`, qui s'applique à défaut."
      },
      "x-flexway-places": [
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.7.0"
    },
    "x-flexway-deliver": {
      "description": "On an AsyncAPI `receive` operation: webhook deliveries of its messages, with no caller - a list of targets `{ upstream, tenant, dead_letter }`. Refused on MQTT 3.1.1 and NATS Core.",
      "items": {
        "additionalProperties": false,
        "properties": {
          "dead_letter": {
            "description": "Dead-letter channel a message goes to when the target did not accept it after the retries; required, without `{` `}` or wildcard.",
            "pattern": "^[^{}*>+#\\s][^{}*>+#]*$",
            "type": "string",
            "x-flexway-description": {
              "en": "Dead-letter channel a message goes to when the target did not accept it after the retries; required, without `{` `}` or wildcard.",
              "fr": "Canal de rebut où va un message que la cible n'a pas accepté après les réessais ; obligatoire, sans `{` `}` ni joker."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.5.0"
          },
          "tenant": {
            "description": "Tenant whose messages are delivered, 1 to 128 characters `[A-Za-z0-9_-]`; required unless the operation is public.",
            "pattern": "^[A-Za-z0-9_-]{1,128}$",
            "type": "string",
            "x-flexway-description": {
              "en": "Tenant whose messages are delivered, 1 to 128 characters `[A-Za-z0-9_-]`; required unless the operation is public.",
              "fr": "Tenant dont les messages sont livrés, 1 à 128 caractères `[A-Za-z0-9_-]` ; obligatoire sauf si l'opération est publique."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.5.0"
          },
          "upstream": {
            "description": "Target, an upstream declared with `protocol: webhook`; required.",
            "type": "string",
            "x-flexway-description": {
              "en": "Target, an upstream declared with `protocol: webhook`; required.",
              "fr": "Cible, un amont déclaré avec `protocol: webhook` ; obligatoire."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.5.0"
          }
        },
        "required": [
          "dead_letter",
          "upstream"
        ],
        "type": "object"
      },
      "type": "array",
      "x-flexway-description": {
        "en": "On an AsyncAPI `receive` operation: webhook deliveries of its messages, with no caller - a list of targets `{ upstream, tenant, dead_letter }`. Refused on MQTT 3.1.1 and NATS Core.",
        "fr": "Sur une opération AsyncAPI `receive` : livraisons webhook de ses messages, sans appelant - une liste de cibles `{ upstream, tenant, dead_letter }`. Refusé en MQTT 3.1.1 et NATS Core."
      },
      "x-flexway-places": [
        "asyncapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.5.0"
    },
    "x-flexway-device": {
      "additionalProperties": false,
      "description": "On an AsyncAPI operation: serves it to devices on the `listeners.mqtt` listener - `send`: a device publishes, `receive`: it subscribes. `true`, or an object of the keys below. Requires an MQTT upstream (one for every device operation), a `security` and a channel whose parameters are bound, the tenant among them; never public.",
      "properties": {
        "bytes_per_second": {
          "description": "On a `send` operation: overrides `listeners.mqtt.device.bytes_per_second` for it.",
          "minimum": 1,
          "type": "integer",
          "x-flexway-description": {
            "en": "On a `send` operation: overrides `listeners.mqtt.device.bytes_per_second` for it.",
            "fr": "Sur une opération `send` : surcharge `listeners.mqtt.device.bytes_per_second` pour elle."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.7.0"
        },
        "messages_per_second": {
          "description": "On a `send` operation: overrides `listeners.mqtt.device.messages_per_second` for it.",
          "exclusiveMinimum": 0,
          "type": "number",
          "x-flexway-description": {
            "en": "On a `send` operation: overrides `listeners.mqtt.device.messages_per_second` for it.",
            "fr": "Sur une opération `send` : surcharge `listeners.mqtt.device.messages_per_second` pour elle."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.7.0"
        },
        "qos_max": {
          "default": 2,
          "description": "Highest QoS on the channel; past it a PUBLISH is refused `0x9B` and a subscription granted at it. From 0 to 2, default 2.",
          "maximum": 2,
          "minimum": 0,
          "type": "integer",
          "x-flexway-description": {
            "en": "Highest QoS on the channel; past it a PUBLISH is refused `0x9B` and a subscription granted at it. From 0 to 2, default 2.",
            "fr": "QoS la plus haute sur le canal ; au-delà un PUBLISH est refusé `0x9B` et un abonnement accordé à elle. De 0 à 2, défaut 2."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.7.0"
        },
        "shared": {
          "default": false,
          "description": "On a `receive` operation: admits shared subscriptions (`$share/<group>/<filter>`), the group written toward the broker in the tenant's name. Default `false`.",
          "type": "boolean",
          "x-flexway-description": {
            "en": "On a `receive` operation: admits shared subscriptions (`$share/<group>/<filter>`), the group written toward the broker in the tenant's name. Default `false`.",
            "fr": "Sur une opération `receive` : admet les abonnements partagés (`$share/<groupe>/<filtre>`), le groupe écrit vers le courtier au nom du tenant. Défaut `false`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.7.0"
        }
      },
      "type": [
        "boolean",
        "object"
      ],
      "x-flexway-description": {
        "en": "On an AsyncAPI operation: serves it to devices on the `listeners.mqtt` listener - `send`: a device publishes, `receive`: it subscribes. `true`, or an object of the keys below. Requires an MQTT upstream (one for every device operation), a `security` and a channel whose parameters are bound, the tenant among them; never public.",
        "fr": "Sur une opération AsyncAPI : la sert aux appareils sur l'écouteur `listeners.mqtt` - `send` : un appareil publie, `receive` : il s'abonne. `true`, ou un objet des clés ci-dessous. Exige un amont MQTT (le même pour toutes les opérations d'appareil), une `security` et un canal aux paramètres liés, le tenant parmi eux ; jamais publique."
      },
      "x-flexway-places": [
        "asyncapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.7.0"
    },
    "x-flexway-encrypt": {
      "description": "On an AsyncAPI message: fields written encrypted by the gateway on the Kafka listener - a non-empty list of dotted paths (`card.number`), without `[`, `]`, `*` or space, no duplicate nor path containing another. JSON message (a declared string field), Avro or Protobuf; requires `kms`.",
      "items": {
        "pattern": "^[^.\\s\\[\\]*]+(\\.[^.\\s\\[\\]*]+)*$",
        "type": "string"
      },
      "maxItems": 255,
      "minItems": 1,
      "type": "array",
      "x-flexway-description": {
        "en": "On an AsyncAPI message: fields written encrypted by the gateway on the Kafka listener - a non-empty list of dotted paths (`card.number`), without `[`, `]`, `*` or space, no duplicate nor path containing another. JSON message (a declared string field), Avro or Protobuf; requires `kms`.",
        "fr": "Sur un message AsyncAPI : champs écrits chiffrés par la passerelle sur l'écouteur Kafka - liste non vide de chemins pointés (`card.number`), sans `[`, `]`, `*` ni espace, sans doublon ni chemin qui en contient un autre. Message JSON (champ de type chaîne déclaré), Avro ou Protobuf ; exige `kms`."
      },
      "x-flexway-places": [
        "asyncapi.message"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.6.0"
    },
    "x-flexway-kafka-proxy": {
      "additionalProperties": false,
      "description": "On an AsyncAPI operation: serves it to native Kafka clients on the `listeners.kafka` listener - `send`: a client produces, `receive`: it reads. Requires a Kafka upstream, a `security` and a channel `<prefix>{tenant}.<name>` bound to the tenant; never public.",
      "properties": {
        "admin_scope": {
          "description": "Scope that opens the bounded administration of the virtual cluster; absent: administration is refused.",
          "minLength": 1,
          "type": "string",
          "x-flexway-description": {
            "en": "Scope that opens the bounded administration of the virtual cluster; absent: administration is refused.",
            "fr": "Portée qui ouvre l'administration bornée du cluster virtuel ; absente : administration refusée."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "cluster": {
          "description": "Name of the virtual cluster, a DNS label of 1 to 63 characters `[a-z0-9-]`; required.",
          "pattern": "^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$",
          "type": "string",
          "x-flexway-description": {
            "en": "Name of the virtual cluster, a DNS label of 1 to 63 characters `[a-z0-9-]`; required.",
            "fr": "Nom du cluster virtuel, une étiquette DNS de 1 à 63 caractères `[a-z0-9-]` ; obligatoire."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "decrypt_scope": {
          "description": "On a `receive` operation only: scope that receives the message's `x-flexway-encrypt` fields in clear; without it, they stay encrypted.",
          "minLength": 1,
          "type": "string",
          "x-flexway-description": {
            "en": "On a `receive` operation only: scope that receives the message's `x-flexway-encrypt` fields in clear; without it, they stay encrypted.",
            "fr": "Sur une opération `receive` seulement : portée qui reçoit en clair les champs `x-flexway-encrypt` du message ; sans elle, ils restent chiffrés."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "transactions": {
          "description": "On a `send` operation only: allows transactional producers. Default `false`.",
          "type": "boolean",
          "x-flexway-description": {
            "en": "On a `send` operation only: allows transactional producers. Default `false`.",
            "fr": "Sur une opération `send` seulement : autorise les producteurs transactionnels. Défaut `false`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        }
      },
      "required": [
        "cluster"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "On an AsyncAPI operation: serves it to native Kafka clients on the `listeners.kafka` listener - `send`: a client produces, `receive`: it reads. Requires a Kafka upstream, a `security` and a channel `<prefix>{tenant}.<name>` bound to the tenant; never public.",
        "fr": "Sur une opération AsyncAPI : la sert aux clients Kafka natifs de l'écouteur `listeners.kafka` - `send` : un client produit, `receive` : il lit. Exige un amont Kafka, une `security` et un canal `<préfixe>{tenant}.<nom>` lié au tenant ; jamais publique."
      },
      "x-flexway-places": [
        "asyncapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.6.0"
    },
    "x-flexway-key": {
      "description": "On an AsyncAPI operation: JSON pointer (starting with `/`) to the ordering key in the message, the Kafka record key; no effect on MQTT and AMQP.",
      "pattern": "^/",
      "type": "string",
      "x-flexway-description": {
        "en": "On an AsyncAPI operation: JSON pointer (starting with `/`) to the ordering key in the message, the Kafka record key; no effect on MQTT and AMQP.",
        "fr": "Sur une opération AsyncAPI : pointeur JSON (commençant par `/`) vers la clé d'ordonnancement dans le message, la clé de l'enregistrement Kafka ; sans effet en MQTT et AMQP."
      },
      "x-flexway-places": [
        "asyncapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.5.0"
    },
    "x-flexway-owner": {
      "additionalProperties": false,
      "description": "In an OpenAPI document's `info` or on an operation, the operation wins: team that answers for the operation, `{ team, contact }`. Shown in the catalogue, never read on the request path.",
      "properties": {
        "contact": {
          "description": "How to reach the team - a channel, a list, a page; 128 characters at most, never a person.",
          "maxLength": 128,
          "type": "string",
          "x-flexway-description": {
            "en": "How to reach the team - a channel, a list, a page; 128 characters at most, never a person.",
            "fr": "Comment joindre l'équipe - un canal, une liste, une page ; 128 caractères au plus, jamais une personne."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "team": {
          "description": "Team name, required, not blank, 128 characters at most.",
          "maxLength": 128,
          "minLength": 1,
          "type": "string",
          "x-flexway-description": {
            "en": "Team name, required, not blank, 128 characters at most.",
            "fr": "Nom de l'équipe, obligatoire, non vide, 128 caractères au plus."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        }
      },
      "required": [
        "team"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "In an OpenAPI document's `info` or on an operation, the operation wins: team that answers for the operation, `{ team, contact }`. Shown in the catalogue, never read on the request path.",
        "fr": "Dans `info` d'un document OpenAPI ou sur une opération, l'opération l'emporte : équipe qui répond de l'opération, `{ team, contact }`. Affichée au catalogue, jamais lue sur le chemin de la requête."
      },
      "x-flexway-places": [
        "openapi.info",
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.2.0"
    },
    "x-flexway-policies": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "items": {
            "type": "string"
          },
          "type": "array"
        }
      ],
      "description": "On an OpenAPI operation: its own level of the chain `global -> host -> routes -> operation`, a list of names from `policies.definitions`; `!name` removes a policy of a broader level.",
      "x-flexway-description": {
        "en": "On an OpenAPI operation: its own level of the chain `global -> host -> routes -> operation`, a list of names from `policies.definitions`; `!name` removes a policy of a broader level.",
        "fr": "Sur une opération OpenAPI : son niveau propre de la chaîne `global -> hôte -> routes -> opération`, une liste de noms de `policies.definitions` ; `!nom` retire une politique d'un niveau plus large."
      },
      "x-flexway-places": [
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.5.0"
    },
    "x-flexway-priority": {
      "default": "normal",
      "description": "On an OpenAPI operation: shedding priority under saturation - `critical` (never shed), `normal` (default) or `sheddable` (shed first).",
      "enum": [
        "critical",
        "normal",
        "sheddable"
      ],
      "type": "string",
      "x-flexway-description": {
        "en": "On an OpenAPI operation: shedding priority under saturation - `critical` (never shed), `normal` (default) or `sheddable` (shed first).",
        "fr": "Sur une opération OpenAPI : priorité de délestage sous saturation - `critical` (jamais délestée), `normal` (défaut) ou `sheddable` (délestée en premier)."
      },
      "x-flexway-places": [
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.0.0"
    },
    "x-flexway-public": {
      "description": "On an AsyncAPI `receive` operation: `true` lets anyone consume it, an anonymous caller included - written, never implied. Refused when the channel binds a parameter or carries the tenant attribute, and with `x-flexway-kafka-proxy`.",
      "type": "boolean",
      "x-flexway-description": {
        "en": "On an AsyncAPI `receive` operation: `true` lets anyone consume it, an anonymous caller included - written, never implied. Refused when the channel binds a parameter or carries the tenant attribute, and with `x-flexway-kafka-proxy`.",
        "fr": "Sur une opération AsyncAPI `receive` : `true` laisse quiconque la consommer, anonyme compris - écrit, jamais déduit. Refusé si le canal lie un paramètre ou porte l'attribut tenant, et avec `x-flexway-kafka-proxy`."
      },
      "x-flexway-places": [
        "asyncapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.5.0"
    },
    "x-flexway-publish": {
      "additionalProperties": false,
      "description": "On an OpenAPI `POST` operation: HTTP door of an AsyncAPI `send` operation, `{ operation, idempotency }`. The body is published as CloudEvents and the `202` answer leaves after the broker's acknowledgement; never with `x-flexway-subscribe`, a cache or a body policy, nor for an anonymous caller.",
      "properties": {
        "idempotency": {
          "description": "`required` refuses a publication without an `Idempotency-Key` header; absent: optional.",
          "enum": [
            "required"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "`required` refuses a publication without an `Idempotency-Key` header; absent: optional.",
            "fr": "`required` refuse une publication sans en-tête `Idempotency-Key` ; absent : facultatif."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        },
        "operation": {
          "description": "Id of the `send` operation of `contracts.asyncapi`, with exactly one message, whose schema is the body's; required.",
          "type": "string",
          "x-flexway-description": {
            "en": "Id of the `send` operation of `contracts.asyncapi`, with exactly one message, whose schema is the body's; required.",
            "fr": "Identifiant de l'opération `send` de `contracts.asyncapi`, à un seul message, dont le schéma est celui du corps ; obligatoire."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        }
      },
      "required": [
        "operation"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "On an OpenAPI `POST` operation: HTTP door of an AsyncAPI `send` operation, `{ operation, idempotency }`. The body is published as CloudEvents and the `202` answer leaves after the broker's acknowledgement; never with `x-flexway-subscribe`, a cache or a body policy, nor for an anonymous caller.",
        "fr": "Sur une opération OpenAPI `POST` : porte HTTP d'une opération AsyncAPI `send`, `{ operation, idempotency }`. Le corps est publié en CloudEvents et la réponse `202` part après l'accusé du courtier ; jamais avec `x-flexway-subscribe`, un cache ou une politique de corps, ni pour un appelant anonyme."
      },
      "x-flexway-places": [
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.5.0"
    },
    "x-flexway-rate-class": {
      "description": "On an OpenAPI operation: rate-limit class, defined by the chain's `rate-limit` policy on every host; absent: `read` or `write` by method.",
      "type": "string",
      "x-flexway-description": {
        "en": "On an OpenAPI operation: rate-limit class, defined by the chain's `rate-limit` policy on every host; absent: `read` or `write` by method.",
        "fr": "Sur une opération OpenAPI : classe de débit, définie par la politique `rate-limit` de la chaîne sur chaque hôte ; absente : `read` ou `write` selon la méthode."
      },
      "x-flexway-places": [
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.4.0"
    },
    "x-flexway-scopes": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "items": {
            "type": "string"
          },
          "type": "array"
        }
      ],
      "description": "On an OpenAPI operation: scopes added to every token alternative of `security` (a string or a list); removes the anonymous alternative, leaves API keys and certificates unchanged. It can only add.",
      "x-flexway-description": {
        "en": "On an OpenAPI operation: scopes added to every token alternative of `security` (a string or a list); removes the anonymous alternative, leaves API keys and certificates unchanged. It can only add.",
        "fr": "Sur une opération OpenAPI : portées ajoutées à chaque alternative à jeton de `security` (une chaîne ou une liste) ; retire l'alternative anonyme, laisse clés d'API et certificats inchangés. Elle ne peut qu'ajouter."
      },
      "x-flexway-places": [
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.3.0"
    },
    "x-flexway-source": {
      "description": "On an AsyncAPI operation: the CloudEvents `source` attribute of what it publishes; absent: `//<request host>/<operation id>`.",
      "type": "string",
      "x-flexway-description": {
        "en": "On an AsyncAPI operation: the CloudEvents `source` attribute of what it publishes; absent: `//<request host>/<operation id>`.",
        "fr": "Sur une opération AsyncAPI : attribut CloudEvents `source` de ce qu'elle publie ; absent : `//<hôte de la requête>/<identifiant de l'opération>`."
      },
      "x-flexway-places": [
        "asyncapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.5.0"
    },
    "x-flexway-sparkplug": {
      "description": "On an AsyncAPI operation served to devices (`x-flexway-device`): its role in the Sparkplug B 3.0 namespace - `edge_node` (channel `spBv1.0/{group}/+/{node}/#`: `send` publishes births, deaths and data, an `NDEATH` will only; `receive` gets its commands), `host` (channel `spBv1.0/{group}/#`: `send` publishes `NCMD` and `DCMD`, every token alternative naming scopes; `receive` reads the group), `state` (channel `spBv1.0/STATE/{host}`, the host bound to the tenant). The group is always bound to the tenant. Without a declared message, the payload is read under the embedded `sparkplug_b.proto` descriptor (validated with `x-flexway-validation: full`).",
      "enum": [
        "edge_node",
        "host",
        "state"
      ],
      "type": "string",
      "x-flexway-description": {
        "en": "On an AsyncAPI operation served to devices (`x-flexway-device`): its role in the Sparkplug B 3.0 namespace - `edge_node` (channel `spBv1.0/{group}/+/{node}/#`: `send` publishes births, deaths and data, an `NDEATH` will only; `receive` gets its commands), `host` (channel `spBv1.0/{group}/#`: `send` publishes `NCMD` and `DCMD`, every token alternative naming scopes; `receive` reads the group), `state` (channel `spBv1.0/STATE/{host}`, the host bound to the tenant). The group is always bound to the tenant. Without a declared message, the payload is read under the embedded `sparkplug_b.proto` descriptor (validated with `x-flexway-validation: full`).",
        "fr": "Sur une opération AsyncAPI servie aux appareils (`x-flexway-device`) : son rôle dans l'espace de noms Sparkplug B 3.0 - `edge_node` (canal `spBv1.0/{groupe}/+/{nœud}/#` : `send` publie naissances, morts et données, testament `NDEATH` seulement ; `receive` reçoit ses commandes), `host` (canal `spBv1.0/{groupe}/#` : `send` publie `NCMD` et `DCMD`, chaque alternative à jeton nommant des portées ; `receive` lit le groupe), `state` (canal `spBv1.0/STATE/{hôte}`, l'hôte lié au tenant). Le groupe est toujours lié au tenant. Sans message déclaré, la charge est lue sous le descripteur `sparkplug_b.proto` embarqué (validation avec `x-flexway-validation: full`)."
      },
      "x-flexway-places": [
        "asyncapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.7.0"
    },
    "x-flexway-subscribe": {
      "additionalProperties": false,
      "description": "On an OpenAPI `GET` operation: a stream of the caller's tenant's messages for an AsyncAPI `receive` operation, as server-sent events or a WebSocket. Anonymous only when the AsyncAPI operation is public; never with `x-flexway-tool`, a cache or a body policy.",
      "properties": {
        "ack_timeout": {
          "default": "30s",
          "description": "Acknowledgement timeout of a WebSocket message, a positive duration; default `30s`.",
          "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
          "type": "string",
          "x-flexway-description": {
            "en": "Acknowledgement timeout of a WebSocket message, a positive duration; default `30s`.",
            "fr": "Délai d'accusé d'un message WebSocket, durée positive ; défaut `30s`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        },
        "buffer": {
          "default": 64,
          "description": "Messages buffered per subscriber, from 1 to 4,096; default 64.",
          "maximum": 4096,
          "minimum": 1,
          "type": "integer",
          "x-flexway-description": {
            "en": "Messages buffered per subscriber, from 1 to 4,096; default 64.",
            "fr": "Messages tamponnés par abonné, de 1 à 4 096 ; défaut 64."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        },
        "frames": {
          "default": "json",
          "description": "Form of WebSocket frames: `json` (default) or `binary`, which requires `websocket` in `transport` and a binary message.",
          "enum": [
            "json",
            "binary"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "Form of WebSocket frames: `json` (default) or `binary`, which requires `websocket` in `transport` and a binary message.",
            "fr": "Forme des trames WebSocket : `json` (défaut) ou `binary`, qui exige `websocket` dans `transport` et un message binaire."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "history": {
          "default": 64,
          "description": "Messages kept in memory per channel for an SSE resume (`Last-Event-ID`), from 0 to 1,024; default 64. `0`: no history, resume refused.",
          "maximum": 1024,
          "minimum": 0,
          "type": "integer",
          "x-flexway-description": {
            "en": "Messages kept in memory per channel for an SSE resume (`Last-Event-ID`), from 0 to 1,024; default 64. `0`: no history, resume refused.",
            "fr": "Messages gardés en mémoire par canal pour une reprise SSE (`Last-Event-ID`), de 0 à 1 024 ; défaut 64. `0` : aucun historique, reprise refusée."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        },
        "max_anonymous_streams": {
          "description": "Anonymous streams open at most, all callers together, per replica; `0` (default): no cap of its own.",
          "minimum": 0,
          "type": "integer",
          "x-flexway-description": {
            "en": "Anonymous streams open at most, all callers together, per replica; `0` (default): no cap of its own.",
            "fr": "Flux anonymes ouverts au plus, tous appelants confondus, par réplique ; `0` (défaut) : sans plafond propre."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        },
        "max_streams": {
          "description": "Streams open at most per caller and replica; `0` (default): no cap of its own.",
          "minimum": 0,
          "type": "integer",
          "x-flexway-description": {
            "en": "Streams open at most per caller and replica; `0` (default): no cap of its own.",
            "fr": "Flux ouverts au plus par appelant et par réplique ; `0` (défaut) : sans plafond propre."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        },
        "operation": {
          "description": "Id of the `receive` operation of `contracts.asyncapi`; required.",
          "type": "string",
          "x-flexway-description": {
            "en": "Id of the `receive` operation of `contracts.asyncapi`; required.",
            "fr": "Identifiant de l'opération `receive` de `contracts.asyncapi` ; obligatoire."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        },
        "transport": {
          "default": [
            "sse",
            "websocket"
          ],
          "description": "Transports offered, a list of `sse` and `websocket`; default: both.",
          "items": {
            "enum": [
              "sse",
              "websocket"
            ],
            "type": "string"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "Transports offered, a list of `sse` and `websocket`; default: both.",
            "fr": "Transports offerts, liste de `sse` et `websocket` ; défaut : les deux."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        }
      },
      "required": [
        "operation"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "On an OpenAPI `GET` operation: a stream of the caller's tenant's messages for an AsyncAPI `receive` operation, as server-sent events or a WebSocket. Anonymous only when the AsyncAPI operation is public; never with `x-flexway-tool`, a cache or a body policy.",
        "fr": "Sur une opération OpenAPI `GET` : flux des messages du tenant de l'appelant pour une opération AsyncAPI `receive`, en SSE ou WebSocket. Anonyme seulement si l'opération AsyncAPI est publique ; jamais avec `x-flexway-tool`, un cache ou une politique de corps."
      },
      "x-flexway-places": [
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.5.0"
    },
    "x-flexway-sunset": {
      "description": "In an OpenAPI document's `info` or on an operation, the operation wins: withdrawal date, `YYYY-MM-DD`. The operation must be `deprecated: true`; set in `info`, every operation without its own value must be.",
      "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
      "type": "string",
      "x-flexway-description": {
        "en": "In an OpenAPI document's `info` or on an operation, the operation wins: withdrawal date, `YYYY-MM-DD`. The operation must be `deprecated: true`; set in `info`, every operation without its own value must be.",
        "fr": "Dans `info` d'un document OpenAPI ou sur une opération, l'opération l'emporte : date de retrait, `AAAA-MM-JJ`. L'opération doit être `deprecated: true` ; posée dans `info`, chaque opération sans valeur propre doit l'être."
      },
      "x-flexway-places": [
        "openapi.info",
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.2.0"
    },
    "x-flexway-timeout": {
      "description": "On an OpenAPI operation: total budget of the operation, retries included, a positive duration (`2s`, `500ms`); overrides `upstreams.*.timeout`, then `server.timeouts.total`.",
      "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
      "type": "string",
      "x-flexway-description": {
        "en": "On an OpenAPI operation: total budget of the operation, retries included, a positive duration (`2s`, `500ms`); overrides `upstreams.*.timeout`, then `server.timeouts.total`.",
        "fr": "Sur une opération OpenAPI : budget total de l'opération, reprises comprises, durée positive (`2s`, `500ms`) ; prime sur `upstreams.*.timeout`, puis `server.timeouts.total`."
      },
      "x-flexway-places": [
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.2.0"
    },
    "x-flexway-tool": {
      "additionalProperties": false,
      "description": "On an OpenAPI operation: offers it as a tool on the MCP surface, under the same decision as REST. `true` (a tool named after the `operationId`), `false`, or an object `{ name, description, unattended }`. Refused with `x-flexway-subscribe` and on an SSE stream.",
      "properties": {
        "description": {
          "description": "Tool description; default: the operation's `summary`, then its `description`.",
          "type": "string",
          "x-flexway-description": {
            "en": "Tool description; default: the operation's `summary`, then its `description`.",
            "fr": "Description de l'outil ; défaut : le `summary`, puis la `description` de l'opération."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.7.0"
        },
        "name": {
          "description": "Tool name, `^[A-Za-z0-9_.-]{1,128}$`, unique per host; default: the `operationId`.",
          "pattern": "^[A-Za-z0-9_.-]{1,128}$",
          "type": "string",
          "x-flexway-description": {
            "en": "Tool name, `^[A-Za-z0-9_.-]{1,128}$`, unique per host; default: the `operationId`.",
            "fr": "Nom de l'outil, `^[A-Za-z0-9_.-]{1,128}$`, unique par hôte ; défaut : l'`operationId`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.7.0"
        },
        "unattended": {
          "default": true,
          "description": "`false` keeps the tool for agents a person supervises; default `true`.",
          "type": "boolean",
          "x-flexway-description": {
            "en": "`false` keeps the tool for agents a person supervises; default `true`.",
            "fr": "`false` réserve l'outil aux agents qu'une personne surveille ; défaut `true`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.0.0"
        }
      },
      "type": [
        "boolean",
        "object"
      ],
      "x-flexway-description": {
        "en": "On an OpenAPI operation: offers it as a tool on the MCP surface, under the same decision as REST. `true` (a tool named after the `operationId`), `false`, or an object `{ name, description, unattended }`. Refused with `x-flexway-subscribe` and on an SSE stream.",
        "fr": "Sur une opération OpenAPI : l'offre en outil sur la surface MCP, sous la même décision qu'en REST. `true` (outil nommé d'après l'`operationId`), `false`, ou un objet `{ name, description, unattended }`. Refusé avec `x-flexway-subscribe` et sur un flux SSE."
      },
      "x-flexway-places": [
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.7.0"
    },
    "x-flexway-upstream": {
      "description": "On an OpenAPI operation: upstream it is relayed to, declared in `upstreams`; absent: the host's `default_upstream`. On an AsyncAPI operation: required, the broker upstream (`kafka`, `amqp`, `mqtt`, `nats`) it publishes to or consumes from.",
      "type": "string",
      "x-flexway-description": {
        "en": "On an OpenAPI operation: upstream it is relayed to, declared in `upstreams`; absent: the host's `default_upstream`. On an AsyncAPI operation: required, the broker upstream (`kafka`, `amqp`, `mqtt`, `nats`) it publishes to or consumes from.",
        "fr": "Sur une opération OpenAPI : amont où elle est relayée, déclaré dans `upstreams` ; absent : `default_upstream` de l'hôte. Sur une opération AsyncAPI : obligatoire, l'amont courtier (`kafka`, `amqp`, `mqtt`, `nats`) où elle publie ou consomme."
      },
      "x-flexway-places": [
        "asyncapi.operation",
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.1.0"
    },
    "x-flexway-validation": {
      "description": "Validation mode of the operation. OpenAPI: `full`, `params` (the body is relayed unread) or `off`, overrides `hosts.*.validation`. AsyncAPI: `full` or `off` only; default `full` for a JSON message (where `off` is refused), `off` for a binary message.",
      "enum": [
        "full",
        "params",
        "off"
      ],
      "type": "string",
      "x-flexway-description": {
        "en": "Validation mode of the operation. OpenAPI: `full`, `params` (the body is relayed unread) or `off`, overrides `hosts.*.validation`. AsyncAPI: `full` or `off` only; default `full` for a JSON message (where `off` is refused), `off` for a binary message.",
        "fr": "Mode de validation de l'opération. OpenAPI : `full`, `params` (le corps est relayé non lu) ou `off`, prime sur `hosts.*.validation`. AsyncAPI : `full` ou `off` seulement ; défaut `full` pour un message JSON (où `off` est refusé), `off` pour un message binaire."
      },
      "x-flexway-places": [
        "asyncapi.operation",
        "openapi.operation"
      ],
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.0.0"
    }
  },
  "$id": "https://flexway.io/schema/v1/contract-extensions.schema.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "The `x-flexway-*` extensions a contract carries (OpenAPI, AsyncAPI, A2A agent card) and the gRPC option `flexway.v1.operation`. A closed list: an `x-flexway-*` extension that is unknown, not served yet or written where it is not read is refused at load.",
  "properties": {
    "x-flexway-a2a": {
      "$ref": "#/$defs/x-flexway-a2a"
    },
    "x-flexway-ai": {
      "$ref": "#/$defs/x-flexway-ai"
    },
    "x-flexway-bind": {
      "$ref": "#/$defs/x-flexway-bind"
    },
    "x-flexway-cache": {
      "$ref": "#/$defs/x-flexway-cache"
    },
    "x-flexway-delegation": {
      "$ref": "#/$defs/x-flexway-delegation"
    },
    "x-flexway-deliver": {
      "$ref": "#/$defs/x-flexway-deliver"
    },
    "x-flexway-device": {
      "$ref": "#/$defs/x-flexway-device"
    },
    "x-flexway-encrypt": {
      "$ref": "#/$defs/x-flexway-encrypt"
    },
    "x-flexway-kafka-proxy": {
      "$ref": "#/$defs/x-flexway-kafka-proxy"
    },
    "x-flexway-key": {
      "$ref": "#/$defs/x-flexway-key"
    },
    "x-flexway-owner": {
      "$ref": "#/$defs/x-flexway-owner"
    },
    "x-flexway-policies": {
      "$ref": "#/$defs/x-flexway-policies"
    },
    "x-flexway-priority": {
      "$ref": "#/$defs/x-flexway-priority"
    },
    "x-flexway-public": {
      "$ref": "#/$defs/x-flexway-public"
    },
    "x-flexway-publish": {
      "$ref": "#/$defs/x-flexway-publish"
    },
    "x-flexway-rate-class": {
      "$ref": "#/$defs/x-flexway-rate-class"
    },
    "x-flexway-scopes": {
      "$ref": "#/$defs/x-flexway-scopes"
    },
    "x-flexway-source": {
      "$ref": "#/$defs/x-flexway-source"
    },
    "x-flexway-sparkplug": {
      "$ref": "#/$defs/x-flexway-sparkplug"
    },
    "x-flexway-subscribe": {
      "$ref": "#/$defs/x-flexway-subscribe"
    },
    "x-flexway-sunset": {
      "$ref": "#/$defs/x-flexway-sunset"
    },
    "x-flexway-timeout": {
      "$ref": "#/$defs/x-flexway-timeout"
    },
    "x-flexway-tool": {
      "$ref": "#/$defs/x-flexway-tool"
    },
    "x-flexway-upstream": {
      "$ref": "#/$defs/x-flexway-upstream"
    },
    "x-flexway-validation": {
      "$ref": "#/$defs/x-flexway-validation"
    }
  },
  "title": "Flexway contract extensions",
  "type": "object",
  "x-flexway-description": {
    "en": "The `x-flexway-*` extensions a contract carries (OpenAPI, AsyncAPI, A2A agent card) and the gRPC option `flexway.v1.operation`. A closed list: an `x-flexway-*` extension that is unknown, not served yet or written where it is not read is refused at load.",
    "fr": "Les extensions `x-flexway-*` qu'un contrat porte (OpenAPI, AsyncAPI, carte d'agent A2A) et l'option gRPC `flexway.v1.operation`. Liste fermée : une extension `x-flexway-*` inconnue, pas encore servie ou écrite là où elle n'est pas lue est refusée au chargement."
  }
}
