{
  "openapi": "3.1.0",
  "info": {
    "title": "Arkadium API",
    "version": "1.1.0",
    "description": "API d'Arkadium per a clients autenticats amb Personal Access Token (PAT). Permet enviar consultes a l'agent ancorat al Meta-Globàlium, gestionar conversaciones (KB-B) i frames d'expressió tematitzada, generar mapes globals i consultar la trajectòria de cobertura dialèctica.\n\n## Autenticació\n\nTotes les crides requereixen un Personal Access Token (PAT) emès des del teu perfil a `https://arkadium.ai/dashboard`. Envia'l com a header:\n\n```\nAuthorization: Bearer ark_pat_<48 hex>\n```\n\nEls tokens es revoquen amb un clic. Documentació de creació i gestió: [arkadium.ai/dashboard](https://arkadium.ai/dashboard).\n\n## Convencions\n\n- Totes les crides POST tenen el cos en JSON. La crida es selecciona via query `?call=<action>`.\n- Resposta sempre JSON (`Content-Type: application/json`).\n- Errors: HTTP 4xx/5xx amb cos `{\"error\": \"<codi>\"}`.\n\n## Novetats 1.2.0 (2026-05-08)\n\n- **Paràmetre `escope`** (request body de `/ask`): control de mode de generació alineat amb l'eix radial PLA-MON del Meta-Globàlium. `-1` general (registre savi, sense bastida visible), `0` equilibrat (default), `+1` focal (concret, citacions verificables). Spec: [`docs/escope-parameter-design.md`](https://arkadium.ai/docs/escope-parameter-design.md).\n- **Generació en dues passades**: per `escope ∈ {-1, 0}` la resposta passa per un poliment savi (wisdom polish) que elimina la bastida estructural (codis cardinals, headings) i preserva la feina dialèctica. La primera passada (draft) s'exposa via `meta.two_pass_first_draft` per transparència.\n- **𝓦 v2 sobre el draft**: la mètrica primària `wisdom_score` reflecteix l'estructura del draft (la feina dialèctica feta). `meta.polished_*` exposa la mateixa mètrica sobre la resposta polida (per anàlisi).\n\n## Novetats 1.1.0 (2026-05-02)\n\n- **Pesos de rellevància** (`category_relevance`): puntuació 0..1 per cada categoria citada, basada en freqüència + èmfasi (encapçalaments, negretes).\n- **Path canònic** (`path`): traça argumental ordenada (ex. `[ANA, SIN, AMO, EXP]`) extreta del marcador `[PATH: …]`.\n- **Mètriques canòniques exteses**: `tempeternal_coverage`, `solve_coagula_balance`, `causal_coverage`, `epistemic_coverage`, `voltes_coverage` per volta.\n- **Re-prompt loop multi-iteració** amb compensació harmònica (Solve-Coagula): `reprompt_iterations`, `reprompt_history`, `reprompt_reason`.\n- **Self-review silenciós** per preguntes definicionals/normatives quan harmonic < 0.85.\n- **Ontologia recuperada** (`retrieved`): hits del RAG sobre la KB-A (Meta-Globàlium canònic).\n- **Memòria d'usuari** (`memory_hits`): fragments de la KB-B privada de l'usuari injectats al context.\n- **Frames** (arquitectura fractal): `/frames` retorna les expressions tematitzades disponibles per centrar la conversa.\n- **Threads (KB-B)**: gestió de fils — `/list_threads`, `/load_thread`, `/save_thread`, `/delete_thread`.\n\n## Llicència\n\nManifest Tècnic 2026 — CC BY-SA 4.0. Codi del framework — Apache 2.0.",
    "contact": {
      "name": "Opengea SCCL",
      "url": "https://arkadium.ai",
      "email": "jordi@opengea.org"
    },
    "license": {
      "name": "Apache 2.0",
      "url": "https://www.apache.org/licenses/LICENSE-2.0"
    }
  },
  "servers": [
    {
      "url": "https://api.arkadium.ai",
      "description": "Producció"
    }
  ],
  "security": [
    {"bearerAuth": []}
  ],
  "tags": [
    {"name": "Agent", "description": "Crides al cicle d'inferència auditable ANA→SIN→AMO→EXP"},
    {"name": "Cobertura", "description": "Trajectòria de cobertura dialèctica (Definició del Bé)"},
    {"name": "Mapa", "description": "Generació de mapes globals 3D per a un tema"},
    {"name": "Frames", "description": "Expressions tematitzades del Meta-Globàlium (arquitectura fractal)"},
    {"name": "Threads", "description": "Gestió de fils de conversa (KB-B)"}
  ],
  "paths": {
    "/": {
      "post": {
        "tags": ["Agent"],
        "summary": "Pregunta a l'agent (cicle ANA→SIN→AMO→EXP)",
        "description": "Envia una consulta a l'agent Arkadium ancorat al Meta-Globàlium. Retorna la resposta generada amb les categories citades, els seus pesos de rellevància, el path canònic, la puntuació harmònica i totes les mètriques estructurals. Si la resposta inicial no compleix els llindars de qualitat (`harmonic_score < 0.75`, cobertura tempeternal incompleta, balanç Solve-Coagula desviat) el sistema dispara un re-prompt iteratiu (`reprompt_history`).",
        "operationId": "ask",
        "parameters": [
          {
            "name": "call",
            "in": "query",
            "required": true,
            "schema": {"type": "string", "enum": ["ask"]},
            "description": "Acció — fixar a `ask`"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {"$ref": "#/components/schemas/AskRequest"}
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resposta generada",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/AskResponse"}
              }
            }
          },
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "500": {"$ref": "#/components/responses/ServerError"}
        }
      }
    },
    "/coverage_summary": {
      "post": {
        "tags": ["Cobertura"],
        "summary": "Estadística de cobertura dialèctica",
        "description": "Retorna la trajectòria de cobertura del verificador estructural sobre el Meta-Globàlium per a l'usuari autenticat: quadrants tocats, score harmònic mitjà, voltes suggerides i biaix detectat.",
        "operationId": "coverage_summary",
        "parameters": [
          {"name": "call", "in": "query", "required": true, "schema": {"type": "string", "enum": ["coverage_summary"]}}
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "window": {
                    "type": "string",
                    "enum": ["all", "7d", "30d", "90d"],
                    "default": "all",
                    "description": "Finestra temporal d'agregació"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resum de cobertura",
            "content": {
              "application/json": {"schema": {"$ref": "#/components/schemas/CoverageSummary"}}
            }
          },
          "401": {"$ref": "#/components/responses/Unauthorized"}
        }
      }
    },
    "/map": {
      "get": {
        "tags": ["Mapa"],
        "summary": "Genera el mapa global d'un tema",
        "description": "Endpoint compatible amb ChatGPT custom plugins. Donat un tema i una resposta XML estructurada per categoria, genera un mapa 3D del Meta-Globàlium amb les categories ressaltades. Retorna HTML que renderitza el mapa.",
        "operationId": "GetGlobalMap",
        "security": [{"bearerAuth": []}, {}],
        "parameters": [
          {
            "name": "topic",
            "in": "query",
            "required": true,
            "schema": {"type": "string"},
            "description": "Tema principal explorat"
          },
          {
            "name": "answer",
            "in": "query",
            "required": true,
            "schema": {"type": "string"},
            "description": "Resposta XML amb les categories i conceptes (vegeu plantilla a instructions.txt)"
          }
        ],
        "responses": {
          "200": {
            "description": "HTML amb el mapa 3D del tema",
            "content": {"text/html": {"schema": {"type": "string"}}}
          }
        }
      }
    },
    "/frames": {
      "post": {
        "tags": ["Frames"],
        "summary": "Llistat de frames (expressions tematitzades)",
        "description": "Retorna les expressions tematitzades disponibles del Meta-Globàlium (arquitectura fractal: 80 principis × 80 expressions = 6400 metacategories objectiu). Cada frame agrupa categories ad-hoc per centrar la conversa en un domini concret (Disciplines, Virtuts, Diàleg i Consens, Pedagogia…).",
        "operationId": "frames",
        "parameters": [
          {"name": "call", "in": "query", "required": true, "schema": {"type": "string", "enum": ["frames"]}}
        ],
        "responses": {
          "200": {
            "description": "Llistat ordenat de frames",
            "content": {
              "application/json": {"schema": {"$ref": "#/components/schemas/FramesResponse"}}
            }
          }
        }
      }
    },
    "/list_threads": {
      "post": {
        "tags": ["Threads"],
        "summary": "Llista els fils de conversa de l'usuari",
        "description": "Retorna fins a 50 fils ordenats per `last_activity` descendent.",
        "operationId": "list_threads",
        "parameters": [
          {"name": "call", "in": "query", "required": true, "schema": {"type": "string", "enum": ["list_threads"]}}
        ],
        "responses": {
          "200": {
            "description": "Llistat de fils",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "threads": {
                      "type": "array",
                      "items": {"$ref": "#/components/schemas/ThreadSummary"}
                    }
                  }
                }
              }
            }
          },
          "401": {"$ref": "#/components/responses/Unauthorized"}
        }
      }
    },
    "/load_thread": {
      "post": {
        "tags": ["Threads"],
        "summary": "Carrega els missatges d'un fil",
        "description": "Retorna els missatges d'un fil amb totes les mètriques estructurals hidratades (persistides a `metrics_json` o recalculades al vol per a rows legacy). Filtra automàticament respostes d'error d'API (`harmonic_score=0` + content `Error …`).",
        "operationId": "load_thread",
        "parameters": [
          {"name": "call", "in": "query", "required": true, "schema": {"type": "string", "enum": ["load_thread"]}}
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["thread_id"],
                "properties": {
                  "thread_id": {"type": "integer"}
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fil amb missatges hidratats",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "thread": {"$ref": "#/components/schemas/ThreadSummary"},
                    "messages": {
                      "type": "array",
                      "items": {"$ref": "#/components/schemas/HistoricalMessage"}
                    }
                  }
                }
              }
            }
          },
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"description": "Fil inexistent o no propietat de l'usuari"}
        }
      }
    },
    "/save_thread": {
      "post": {
        "tags": ["Threads"],
        "summary": "Crea o renomena un fil",
        "description": "Si `thread_id` està present, renomena el fil existent. Si no, crea un nou fil i retorna el `thread_id`.",
        "operationId": "save_thread",
        "parameters": [
          {"name": "call", "in": "query", "required": true, "schema": {"type": "string", "enum": ["save_thread"]}}
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "thread_id": {"type": "integer", "nullable": true},
                  "title": {"type": "string", "maxLength": 255}
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fil desat",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "thread_id": {"type": "integer"},
                    "ok": {"type": "boolean"}
                  }
                }
              }
            }
          },
          "401": {"$ref": "#/components/responses/Unauthorized"}
        }
      }
    },
    "/delete_thread": {
      "post": {
        "tags": ["Threads"],
        "summary": "Esborra un fil (soft-delete)",
        "description": "Marca el fil com a `status=0` (no es retorna a `/list_threads` ni `/load_thread`).",
        "operationId": "delete_thread",
        "parameters": [
          {"name": "call", "in": "query", "required": true, "schema": {"type": "string", "enum": ["delete_thread"]}}
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["thread_id"],
                "properties": {"thread_id": {"type": "integer"}}
              }
            }
          }
        },
        "responses": {
          "200": {"description": "OK"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"description": "Fil inexistent o no propietat de l'usuari"}
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "ark_pat_<48 hex>",
        "description": "Personal Access Token emès des del perfil de l'usuari a [arkadium.ai/dashboard](https://arkadium.ai/dashboard)."
      }
    },
    "schemas": {
      "AskRequest": {
        "type": "object",
        "required": ["question"],
        "properties": {
          "question": {
            "type": "string",
            "description": "La consulta de l'usuari en llenguatge natural",
            "example": "Què es el bé?"
          },
          "userLanguage": {
            "type": "string",
            "description": "Codi ISO 639-1 (`ca`, `en`, `es`...). Si no es proporciona, l'agent detecta la llengua de la pregunta.",
            "example": "ca"
          },
          "agent": {
            "type": "string",
            "default": "arkadium",
            "description": "Identificador de l'agent. `arkadium` és l'únic ancorat al Meta-Globàlium amb cicle complet ANA→SIN→AMO→EXP, verificador estructural i re-prompt loop."
          },
          "provider": {
            "type": "string",
            "enum": ["openai", "anthropic"],
            "default": "openai",
            "description": "Proveïdor de LLM subjacent"
          },
          "model": {
            "type": "string",
            "description": "Model concret del proveïdor (opcional — agafa el default si s'omet)",
            "example": "claude-sonnet-4-6"
          },
          "sessionId": {
            "type": "string",
            "description": "Identificador opcional per a continuar un fil de conversa stateless"
          },
          "thread_id": {
            "type": "integer",
            "description": "ID del fil persistit a la KB-B. Si s'omet i hi ha context d'usuari, el sistema el crea automàticament.",
            "nullable": true
          },
          "active_frame_id": {
            "type": "integer",
            "description": "ID d'un frame d'expressió tematitzada (vegeu `/frames`). Si està present, l'agent injecta el context tematitzat al system prompt. Omet o usa 28 (Meta-Globàlium principis) per al substrat universal.",
            "nullable": true
          },
          "escope": {
            "type": "integer",
            "enum": [-1, 0, 1],
            "default": 0,
            "description": "Mode de generació alineat amb l'eix radial PLA-MON del Meta-Globàlium: `-1` general (resposta integradora i holística, sense bastida estructural visible — wisdom register), `0` equilibrat (predeterminat: estructura dialèctica + registre savi), `+1` focal (resposta concreta amb autors, dates i casos verificables — evidence register). Spec: `docs/escope-parameter-design.md`.",
            "example": 0
          },
          "two_pass": {
            "type": "boolean",
            "nullable": true,
            "description": "Override per la generació en dues passades. `null` (default) = el servidor decideix per `escope` (∈{-1,0} → true, +1 → false). `false` desactiva el polish savi (útil per diagnòstic). `true` força el polish també a focal (no recomanat: trenca el principi del mode focal de mantenir l'estructura visible)."
          }
        }
      },
      "AskResponse": {
        "type": "object",
        "properties": {
          "answer": {
            "type": "object",
            "description": "Resposta crua del proveïdor LLM (format compatible amb OpenAI Chat Completions). El text final està a `answer.choices[0].message.content`."
          },
          "meta": {
            "type": "object",
            "properties": {
              "provider": {"type": "string"},
              "model":    {"type": "string"},
              "agent":    {"type": "string"},
              "escope":   {"type": "integer", "enum": [-1, 0, 1], "description": "Valor d'escope efectivament aplicat a aquesta crida."},
              "two_pass_applied": {"type": "boolean", "description": "Si la passada de poliment savi (wisdom polish) s'ha aplicat. Nominal per `escope ∈ {-1, 0}`; sempre `false` per `escope = +1`."},
              "two_pass_first_draft": {"type": "string", "nullable": true, "description": "Text de la primera passada (pre-poliment) si `two_pass_applied`. Conté la bastida estructural (codis cardinals, headings, mediadors anomenats) que el poliment elimina de la resposta visible. Exposat per transparència — frontend ho mostra com a `<details>` plegat (\"veure el procés\")."},
              "polished_wisdom_score": {"type": "number", "format": "float", "nullable": true, "description": "𝓦 v2 calculat sobre la resposta polida (no visible) — només per anàlisi. Tendeix a ser baix perquè el polish elimina codis cardinals que 𝓦 mesura. La mètrica primària `wisdom_score` reflecteix el draft."},
              "polished_harmonic_score": {"type": "number", "format": "float", "nullable": true, "description": "𝓗 calculat sobre la resposta polida — només per anàlisi (vegeu `polished_wisdom_score`)."}
            }
          },
          "categories_touched": {
            "type": "array",
            "description": "Codis de categoria del Meta-Globàlium citats al text de la resposta (extracció regex sobre whitelist).",
            "items": {"type": "string"},
            "example": ["NOU", "AMO", "ETI", "HAR", "SIN"]
          },
          "category_relevance": {
            "type": "object",
            "description": "Mapa codi → pes ∈ [0..1] segons freqüència de citació i èmfasi (encapçalaments x2, negretes +1). El frontend l'usa per ordenar chips i pintar el degradat al model 3D.",
            "additionalProperties": {"type": "number", "format": "float"},
            "example": {"NOU": 1.0, "AMO": 0.8, "HAR": 0.6}
          },
          "harmonic_score": {
            "type": "number",
            "format": "float",
            "minimum": 0.0,
            "maximum": 1.0,
            "description": "Puntuació de compensació harmònica de la resposta (Definició del Bé). Combina cobertura quadrants + entropia."
          },
          "path": {
            "type": "array",
            "description": "Recorregut canònic ordenat extret del marcador `[PATH: …]` (per a preguntes definicionals/procedimentals). Habitualment ANA→SIN→AMO→EXP o variants.",
            "items": {"type": "string"},
            "example": ["ANA", "SIN", "AMO", "EXP"]
          },
          "voltes_suggested": {
            "type": "array",
            "description": "Voltes del Mètode Global mencionades o detectades a la resposta",
            "items": {"type": "string"},
            "example": ["Mètode", "Coneixement"]
          },
          "voltes_coverage": {
            "type": "object",
            "description": "Per cada volta detectada, mètriques de cobertura: estacions tocades, % de cobertura, hits/total.",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "coverage": {"type": "number", "format": "float"},
                "hits": {"type": "integer"},
                "total": {"type": "integer"},
                "stations_touched": {"type": "array", "items": {"type": "string"}}
              }
            }
          },
          "tempeternal_coverage": {
            "type": "number",
            "format": "float",
            "description": "Cobertura tempeternal D4 (PLA/Neutral/MON). 1.0 = saviesa integral; ≤0.67 dispara re-prompt."
          },
          "tempeternal_balance": {"type": "number", "format": "float"},
          "pla_side_count": {"type": "integer", "description": "Nombre de citacions a categories Plasmàtiques (essencial/atemporal)"},
          "neu_side_count": {"type": "integer", "description": "Nombre de citacions a categories Neutrals (dialèctiques)"},
          "mon_side_count": {"type": "integer", "description": "Nombre de citacions a categories Mundanes (concret/temporal)"},
          "solve_coagula_balance": {
            "type": "number",
            "format": "float",
            "description": "Balanç ANA+CIE (Solve) vs SIN+MTP (Coagula) en el viatge FEN→NOU. Aplica només a essencialitzacions; <0.3 dispara re-prompt."
          },
          "solve_count": {"type": "integer"},
          "coagula_count": {"type": "integer"},
          "causal_coverage": {
            "type": "number",
            "format": "float",
            "description": "Cobertura causal aristotèlica (7 causes: material/formal/final/eficient/exemplar/contextual/essencial)."
          },
          "causes_touched": {"type": "array", "items": {"type": "string"}},
          "epistemic_coverage": {
            "type": "number",
            "format": "float",
            "description": "Cobertura epistemològica (4 tipus: deducció/inducció/abducció-selectiva/abducció-creativa)."
          },
          "inferences_touched": {"type": "array", "items": {"type": "string"}},
          "verification_meta": {
            "type": "object",
            "properties": {
              "quadrants_touched": {"type": "array", "items": {"type": "string"}},
              "n_quadrants": {"type": "integer"},
              "needs_reprompt": {"type": "boolean"},
              "missing_quadrants": {"type": "array", "items": {"type": "string"}}
            }
          },
          "retrieved": {
            "type": "array",
            "description": "Hits del RAG sobre la KB-A (Meta-Globàlium canònic) que han informat el system prompt. NO són necessàriament citats al text.",
            "items": {"$ref": "#/components/schemas/RetrievedHit"}
          },
          "memory_hits": {
            "type": "array",
            "description": "Fragments de la KB-B privada de l'usuari (memòria persistent) injectats al context.",
            "items": {"$ref": "#/components/schemas/MemoryHit"}
          },
          "reprompt_iterations": {
            "type": "integer",
            "description": "Nombre d'iteracions de re-prompt aplicades. 0 = resposta acceptada al primer intent."
          },
          "reprompt_reason": {
            "type": "string",
            "nullable": true,
            "enum": [null, "low_dispersion", "solve_coagula_imbalance", "tempeternal_partial", "low_harmonic", "self_review", "multi_signal"],
            "description": "Raó de l'última iteració. `self_review` = pas silenciós d'autocrítica per definicionals/normatives."
          },
          "reprompt_history": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "iteration": {"type": "integer"},
                "harmonic_score": {"type": "number", "format": "float"},
                "delta": {"type": "number", "format": "float"},
                "reason": {"type": "string"}
              }
            }
          },
          "reprompt_max_iterations": {"type": "integer", "default": 2},
          "reprompt_attempted": {"type": "boolean"},
          "thread_id": {"type": "integer", "nullable": true, "description": "ID del fil on s'ha persistit la resposta (KB-B)"}
        }
      },
      "RetrievedHit": {
        "type": "object",
        "description": "Categoria recuperada pel RAG sobre la KB-A canònica",
        "properties": {
          "id": {"type": "integer"},
          "label": {"type": "string", "example": "HAR"},
          "nom": {"type": "string"},
          "tipus": {"type": "string", "enum": ["pla", "neu", "mun", "Plasmàtica", "Neutral", "Mundana"]},
          "score": {"type": "number", "format": "float"}
        }
      },
      "MemoryHit": {
        "type": "object",
        "description": "Fragment de memòria d'usuari (KB-B)",
        "properties": {
          "id": {"type": "integer"},
          "kind": {"type": "string"},
          "content_excerpt": {"type": "string", "maxLength": 100},
          "score": {"type": "number", "format": "float"},
          "created_at": {"type": "string", "format": "date-time"}
        }
      },
      "FramesResponse": {
        "type": "object",
        "properties": {
          "default_id": {"type": "integer", "example": 28, "description": "ID del frame default (Meta-Globàlium principis)"},
          "frames": {
            "type": "array",
            "items": {"$ref": "#/components/schemas/Frame"}
          },
          "count": {"type": "integer"}
        }
      },
      "Frame": {
        "type": "object",
        "properties": {
          "id": {"type": "integer"},
          "label": {"type": "string"},
          "nom": {"type": "string"},
          "name_en": {"type": "string"},
          "parent": {"type": "integer"},
          "metaparent": {"type": "integer"},
          "category_count": {"type": "integer", "description": "Nombre de metacategories. Per a Meta-Globàlium (id=28) val 6400 (target fractal)."},
          "category_completeness": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 1,
            "description": "Fracció de metacategories realment poblades respecte al target."
          },
          "icon_fa": {"type": "string", "description": "Classe Font Awesome de l'icona representativa"},
          "icon_class_extra": {"type": "string"},
          "description_short": {"type": "string"},
          "is_recommended": {"type": "boolean"},
          "group": {"type": "string", "enum": ["universal", "tematitzada", "unclassified"]},
          "display_order": {"type": "integer"}
        }
      },
      "ThreadSummary": {
        "type": "object",
        "properties": {
          "id": {"type": "integer"},
          "title": {"type": "string"},
          "last_activity": {"type": "string", "format": "date-time"},
          "summary": {"type": "string", "nullable": true}
        }
      },
      "HistoricalMessage": {
        "type": "object",
        "description": "Missatge d'un fil amb mètriques estructurals hidratades (recuperades de `metrics_json` o recalculades).",
        "properties": {
          "role": {"type": "string", "enum": ["user", "assistant", "system"]},
          "content": {"type": "string"},
          "categories_touched": {"type": "array", "items": {"type": "string"}},
          "harmonic_score": {"type": "number", "format": "float", "nullable": true},
          "path": {"type": "array", "items": {"type": "string"}},
          "category_relevance": {
            "type": "object",
            "additionalProperties": {"type": "number", "format": "float"}
          },
          "voltes_suggested": {"type": "array", "items": {"type": "string"}},
          "voltes_coverage": {"type": "object"},
          "tempeternal_coverage": {"type": "number", "format": "float"},
          "tempeternal_balance":  {"type": "number", "format": "float"},
          "pla_side_count": {"type": "integer"},
          "neu_side_count": {"type": "integer"},
          "mon_side_count": {"type": "integer"},
          "solve_coagula_balance": {"type": "number", "format": "float"},
          "solve_count": {"type": "integer"},
          "coagula_count": {"type": "integer"},
          "causal_coverage": {"type": "number", "format": "float"},
          "causes_touched": {"type": "array", "items": {"type": "string"}},
          "epistemic_coverage": {"type": "number", "format": "float"},
          "inferences_touched": {"type": "array", "items": {"type": "string"}},
          "retrieved": {"type": "array", "items": {"$ref": "#/components/schemas/RetrievedHit"}},
          "created_at": {"type": "string", "format": "date-time"}
        }
      },
      "CoverageSummary": {
        "type": "object",
        "properties": {
          "n_interactions": {"type": "integer", "description": "Nombre d'interaccions agregades a la finestra"},
          "quadrants_distribution": {
            "type": "object",
            "description": "Distribució (% del total) dels 8 quadrants del Meta-Globàlium",
            "additionalProperties": {"type": "number"}
          },
          "harmonic_score_avg": {"type": "number", "format": "float"},
          "voltes_suggested": {
            "type": "array",
            "description": "Voltes del Mètode Global suggerides per compensar biaix detectat",
            "items": {"type": "string"}
          },
          "bias_detected": {
            "type": "string",
            "nullable": true,
            "description": "Quadrant amb biaix sistemàtic, si n'hi ha"
          }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Token absent, malformat o revocat",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {"error": {"type": "string", "example": "not_authenticated"}}
            }
          }
        }
      },
      "ServerError": {
        "description": "Error intern",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {"error": {"type": "string"}}
            }
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Manifest Tècnic 2026",
    "url": "https://arkadium.ai/manifest/"
  }
}
