#  Copyright (c) 2026 Cisco Systems, Inc. and its affiliates
#  SPDX-License-Identifier: Apache-2.0
$schema: "https://json-schema.org/draft-07/schema#"
$id: "mas/v1#flavour"
title: "Flavour Manifest"
description: >
  Schema for kind: Flavour manifests.

  A Flavour is a *deployment posture* — it selects protocols and
  observability/control plugins. It does NOT own model names, LLM inference
  parameters, skills/RAG configuration, or infrastructure coordinates.
  Those concerns belong to:

    * kind: Agent  (spec.models, spec.skills)  — model choice, inference
                                                  params, RAG backend
    * kind: MAS    (spec.agency)                — topology / orchestration
    * infra/v1 RuntimeEngine (workspace runtime_refs, --runtime-ref) — cache
                                                    policy, stream, queue depth
    * infra/v1 LLMProxy / provider bundle (workspace infra_refs) — LLM endpoint,
                                                    including standard:openai
    * infra/v1     (LLMProxy, InfraBundle)       — api_base, api_key_env,
                                                    allowed models, embed
                                                    defaults

  A typical Flavour only needs:
    spec:
      agent_comm: {protocol: local, mode: local, emulation: true}
      tools: {remote_tools_enabled: false, allowed: ["*"]}
      telemetry: {backend: file, path: logs/}
      observability: [native]

  Infrastructure references (infra_refs) are NOT part of the Flavour — they
  belong in config.yaml or on the CLI (--infra-ref).  This separation
  keeps flavours portable and reusable across deployments.

  FORBIDDEN (rejected by FlavourSeparationValidator at load time): spec.llm,
  spec.skills, spec.prefer_local. These belong on kind: Agent / workspace
  infra and runtime refs — a flavour that still declares them is carrying
  model-selection or execution-mode state that doesn't belong to a deployment
  posture.

type: object
required:
  - apiVersion
  - kind
  - metadata
  - spec
additionalProperties: false
patternProperties:
  "^x-":
    description: "Extension properties (UI metadata, canvas state, etc.) — ignored by the runtime."

properties:
  apiVersion:
    type: string
    description: "API version — 'flavour/v1'."

  kind:
    type: string
    const: "Flavour"

  metadata:
    type: object
    additionalProperties: true
    properties:
      name:
        type: string
      version:
        type: string
      description:
        type: string
      tags:
        type: array
        items:
          type: string

  spec:
    type: object
    additionalProperties: true
    description: >
      Flavour specification. All sub-objects are additionalProperties: true to
      remain forward-compatible as new sections are added.

      NOTE: infra_refs / infra_ref are NOT allowed here — infrastructure
      references belong in config.yaml or on the CLI (--infra-ref). The
      separation validator rejects flavours that include them.
    properties:
      agent_comm:
        type: object
        x-merge:
          strategy: mapping_merge_or_ops
        additionalProperties: true
        description: "Agent-to-agent communication settings."
        properties:
          protocol:
            type: string
            description: "local | grpc | hybrid"
          mode:
            type: string
            description: "local | remote"
          emulation:
            type: boolean
          agents:
            type: object
            additionalProperties:
              type: string
            description: "agent-id → socket/TCP address (grpc/hybrid protocols only)"

      capabilities:
        type: object
        x-merge:
          strategy: mapping_merge_or_ops
        additionalProperties: true
        description: "Feature flags and capability overrides."

      telemetry:
        type: object
        x-merge:
          strategy: mapping_merge_or_ops
        additionalProperties: true
        description: "Basic telemetry / log sink configuration."
        properties:
          backend:
            type: string
            description: "file | none"
          path:
            type: string

      observability:
        oneOf:
          - type: "null"
          - $ref: "./fragments/observability-binding.schema.yaml"
        x-merge:
          strategy: plugin_list_ops
          identity: plugin_id
        description: >
          Observability sink plugin selection (e.g. [native], [otel],
          [native, {otel: {output_path: traces/otel}}]). This is the
          deployment-posture concern the guiding principle refers to — a
          flavour selects *which* plugins run, not backend/span-export
          internals. local → [native].
        default: null

      control:
        oneOf:
          - type: "null"
          - $ref: "./fragments/control-binding.schema.yaml"
        x-merge:
          strategy: mapping_ops
        description: "Control-plane plugin selection (budget, circuit_breaker, rate_limiter)."
        default: null

      tools:
        type: object
        x-merge:
          strategy: mapping_merge_or_ops
        additionalProperties: true
        description: "Tool deployment posture and provider selection."
        properties:
          exposure_protocol:
            type: string
            enum: [mcp]
            description: Protocol used to expose this app's local tools.
          remote_tools_enabled:
            type: boolean
          allowed:
            type: array
            items:
              type: string

      config:
        type: object
        x-merge:
          strategy: mapping_merge_or_ops
        additionalProperties: true
        description: >
          Free-form deployment config: infrastructure URLs, non-secret
          identifiers, feature flags.  Never place secret values here — use
          api_key_env references in infra manifests instead.

      operator:
        type: object
        x-merge:
          strategy: mapping_merge_or_ops
        additionalProperties: true
        description: "Operator / provisioner metadata."
