# GENERATO DA bin/contratto-v1.js — NON SI MODIFICA A MANO.
# Ogni voce è derivata da src/routes/v1/index.js: metodo e percorso dalla
# dichiarazione della rotta, `x-permesso` da conPermesso(), `x-freno` da
# limiti.*, la descrizione dal commento che la precede.
# Gli schemi delle risposte NON sono dichiarati nel codice: qui restano
# aperti apposta. Un contratto che inventa una forma è peggio di uno che tace.
# La guardia contro la deriva è test/contratto-v1.test.js.
openapi: 3.0.3
info:
  title: ADP — Persona as a Service (/v1)
  version: "1"
  description: |-
    La porta che un programma di un cliente usa per far vivere la sua persona
    digitale. Non entra un browser: niente cookie, niente CSRF — la chiave è
    l'autenticazione.
    
    L'ordine dei passi di ogni chiamata è sempre lo stesso: riconosci la
    chiave, autorizza PRIMA di fare, fai, registra il consumo.
servers:
  - url: /v1
components:
  securitySchemes:
    chiaveBearer:
      type: http
      scheme: bearer
      description: "La chiave della persona in Authorization: Bearer"
    chiavePersona:
      type: apiKey
      in: header
      name: X-Persona-Key
      description: "La stessa chiave, per i client che gestiscono meglio un header proprio"
  responses:
    ChiaveNonValida:
      description: >-
        401 — chiave assente, sconosciuta, sospesa o revocata. I quattro casi
        sono indistinguibili di proposito: chi prova chiavi a caso non deve
        imparare niente dalla risposta.
    ChiaveGiustaMaBloccata:
      description: >-
        423 — la chiave è giusta, ma qualcosa sopra di lei è fermo. Due casi, e
        il corpo dice QUALE: `persona_sospesa` (la persona è sospesa
        dall'area riservata) e `licenza_non_in_vigore` (la licenza sotto cui
        sta la chiave è sospesa, scaduta, revocata o non ancora valida — il
        corpo porta anche lo stato effettivo).
        Qui il perché si dice: chi ha la chiave giusta è il proprietario.
    QuotaEsaurita:
      description: >-
        429 — quota finita. Porta tetto, usato e finestra, e un Retry-After
        con i secondi che mancano perché il consumo più vecchio esca dalla finestra.
security:
  - chiaveBearer: []
  - chiavePersona: []
paths:
  "/persona":
    get:
      operationId: "getPersona"
      description: |-
        La carta d'identità della persona: che cosa sa fare, con che vincoli, e
        quanto le resta. È la prima chiamata che chiunque fa, e deve bastare a
        capire tutto il resto senza leggere una documentazione.
      x-sorgente: "src/routes/v1/index.js:352"
      x-permesso: "persona.descrivi"
      x-freno: "navigazione"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/consumi":
    get:
      operationId: "getConsumi"
      description: |-
        Il consumo, da solo: è la chiamata che un cliente mette in un cruscotto.
      x-sorgente: "src/routes/v1/index.js:401"
      x-permesso: "persona.descrivi"
      x-freno: "navigazione"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/messaggi/invia":
    post:
      operationId: "postMessaggiInvia"
      description: |-
        Un messaggio alla persona. È Persona-as-a-Service che mantiene la promessa:
        il sistema del cliente scrive, la persona risponde, e la memoria è unica
        attraverso i canali.
        
        Ordine: autorizza (scope+quota, PRIMA) → esegui → registra il consumo DOPO,
        con i token veri. La stima per l'autorizzazione è 1 richiesta; il costo
        registrato è quello effettivo.
      x-sorgente: "src/routes/v1/index.js:419"
      x-permesso: "messaggi.invia"
      x-freno: "preventivo"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "400":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
        "503":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
  "/memoria/{interlocutore}":
    parameters:
      - name: interlocutore
        in: path
        required: true
        schema: { type: string }
    get:
      operationId: "getMemoriaInterlocutore"
      description: |-
        La memoria di un interlocutore, come la vede la persona.
      x-sorgente: "src/routes/v1/index.js:491"
      x-permesso: "memoria.leggi"
      x-freno: "navigazione"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/memoria/{interlocutore}/dimentica":
    parameters:
      - name: interlocutore
        in: path
        required: true
        schema: { type: string }
    post:
      operationId: "postMemoriaInterlocutoreDimentica"
      description: |-
        Il diritto all'oblio, via API. Il cliente è titolare del trattamento dei SUOI
        interlocutori: quando un suo cliente chiede la cancellazione, questa è la
        strada — e cancella davvero, non azzera campi.
      x-sorgente: "src/routes/v1/index.js:519"
      x-permesso: "memoria.dimentica"
      x-freno: "preventivo"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/memoria/{interlocutore}/collega":
    parameters:
      - name: interlocutore
        in: path
        required: true
        schema: { type: string }
    post:
      operationId: "postMemoriaInterlocutoreCollega"
      x-sorgente: "src/routes/v1/index.js:559"
      x-permesso: "memoria.collega"
      x-freno: "preventivo"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "400":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "409":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/memoria/{interlocutore}/collega/conferma":
    parameters:
      - name: interlocutore
        in: path
        required: true
        schema: { type: string }
    post:
      operationId: "postMemoriaInterlocutoreCollegaConferma"
      description: |-
        La conferma: il codice arrivato sul canale nuovo, digitato su quello vecchio.
      x-sorgente: "src/routes/v1/index.js:612"
      x-permesso: "memoria.collega"
      x-freno: "preventivo"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "409":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/voce/sintetizza":
    post:
      operationId: "postVoceSintetizza"
      description: |-
        Sintesi vocale: testo dentro, audio fuori.
        
        La quantità per la quota `minuti_voce` è **caratteri/1000, arrotondati per
        eccesso al centesimo di minuto**: mille caratteri di parlato italiano stanno
        in un minuto abbondante (~160 parole al minuto). Qui la stima è anche la
        misura — non esiste una durata «vera» prima di aver generato l'audio, e
        misurarla dopo vorrebbe dire decodificare l'MP3 per fatturarlo. Il centesimo
        di minuto evita che una risposta di due righe costi come un minuto intero.
        
        La risposta è **binaria**: non c'è JSON attorno all'audio, e i dati che
        servono a chi integra (motore, asse di esecuzione, minuti addebitati) stanno
        nelle intestazioni.
      x-sorgente: "src/routes/v1/index.js:719"
      x-permesso: "voce.sintetizza"
      x-freno: "preventivo"
      x-stati-dinamici: "err.stato"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/voce/trascrivi":
    post:
      operationId: "postVoceTrascrivi"
      description: |-
        Trascrizione: audio dentro, testo fuori.
        
        L'audio arriva in **base64 dentro il JSON**, coerente con l'unico parser
        montato su questa porta. Il tetto è quello del corpo JSON
        (`config.limits.jsonBodyBytes`, variabile `ADP_JSON_LIMIT`): oltre quello
        risponde 413 il parser, prima ancora di arrivare qui. Chi deve trascrivere
        minuti di parlato alza quella variabile — non serve toccare il codice.
        
        La quantità per la quota è la **durata vera** tornata dal fornitore, non la
        stima: la stima (byte/bitrate) serve solo ad aprire il cancello prima di
        spendere, ed è volutamente prudente. Fatturare una stima significherebbe
        mettere in bolletta un'ipotesi.
      x-sorgente: "src/routes/v1/index.js:775"
      x-permesso: "voce.trascrivi"
      x-freno: "preventivo"
      x-stati-dinamici: "err.stato"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/voce/turno":
    post:
      operationId: "postVoceTurno"
      description: |-
        UN TURNO DI VOCE INTERO: audio dentro, audio fuori.
        
        ── PERCHÉ ESISTE (5/10/2026) ──────────────────────────────────────────────
        Dal 5/10 i due organi sovrani hanno il loro adattatore, e il giro
        «testo → voce → orecchie → testo» l'ho misurato: funziona. Ma esisteva **a
        pezzi**: chi integra doveva fare **tre** chiamate (`/voce/trascrivi`,
        `/messaggi/invia`, `/voce/sintetizza`), tenersi il testo in mano fra l'una e
        l'altra e ricucire i conti. Un canale vero — una telefonata, un vocale
        WhatsApp — non ha nessuna voglia di farlo, e ogni integratore lo ricucirebbe
        a modo suo. Questa è la cucitura, fatta una volta e qui.
        
        ⚠️ **NON è un organo nuovo e non vende niente di nuovo**: sono i tre che la
        persona ha già, nell'ordine. Servono **tutti e tre** gli scope, e si
        verificano **prima di spendere**: chi non ha comprato la voce non ottiene
        audio facendo passare la richiesta da qui.
        
        ── I CONTI, UNO PER ORGANO ────────────────────────────────────────────────
        Tre consumi distinti, ognuno **registrato solo quando quell'organo ha
        davvero reso** — e sulla sua quota, con la sua unità:
          orecchie  `minuti_voce`      la durata VERA tornata dal fornitore;
          cervello  `richieste_giorno` una richiesta;
          voce      `minuti_voce`      i caratteri della risposta / 1000.
        Fatturarli insieme a fine giro, o sommarli in un numero solo, renderebbe
        illeggibile il conto di chi integra — e `/consumi` li distingue già.
        
        ── E SE L'ULTIMO PEZZO CADE ───────────────────────────────────────────────
        🔴 La risposta **non si butta**. Se la sintesi fallisce (fornitore giù, o la
        quota della voce finita *durante* il turno), il cliente ha già ricevuto il
        valore — la persona ha capito e ha risposto — e quel valore si consegna:
        `audio: null` + **`audioNota`** col motivo in italiano, e i due consumi che
        sono stati resi restano registrati. Buttare tutto vorrebbe dire far pagare la
        trascrizione e il pensiero per poi non dare niente.
        È la stessa forma di `personaConvocata`/`personaNota` della videochat: un
        esito parziale si **dichiara**, non si nasconde dietro un errore.
        
        ── CHE COSA NON FA, detto qui e non scoperto dopo ─────────────────────────
        · **non è a flusso**: si parla, poi si pensa, poi si risponde. I tempi dei
          tre pezzi stanno in `tempi`, perché «è lento» senza il soggetto non è una
          diagnosi;
        · **non apre un canale**: non suona un telefono e non legge WhatsApp. Il
          `canale` lo DICHIARA chi integra, ed è uno di quelli che la memoria unica
          conosce già (`telefono` per difetto) — nessun canale nuovo inventato qui,
          o la memoria di un interlocutore si spezzerebbe in due;
        · **l'audio va e torna in base64 dentro il JSON**, come `/voce/trascrivi`:
          un turno intero non si può consegnare in binario, perché il testo sentito e
          la risposta scritta servono a chi integra tanto quanto il suono. ⚠️ Il
          base64 costa **un terzo in più** di byte: il tetto è quello del corpo JSON
          (`ADP_JSON_LIMIT`), e chi manda minuti di parlato lo alza.
      x-sorgente: "src/routes/v1/index.js:868"
      x-permesso: "voce.trascrivi"
      x-freno: "preventivo"
      x-stati-dinamici: "err.stato"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "400":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
        "503":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
  "/videochat/apri":
    post:
      operationId: "postVideochatApri"
      x-sorgente: "src/routes/v1/index.js:1085"
      x-permesso: "videochat.apri"
      x-freno: "preventivo"
      x-stati-dinamici: "stato"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/videochat/chiudi":
    post:
      operationId: "postVideochatChiudi"
      description: |-
        LA VIDEOCHAT SI CHIUDE, E CHIUDENDOLA SI PAGA LA DURATA (D4).
        
        🔴 Perché questa rotta esiste. Il listino vende `minuti_videochat` in
        **minuti/mese** (0,75 EUR/minuto) e fino a oggi l'unica scrittura su quella
        quota era l'**1 fisso** dell'apertura: una videochat di due ore costava un
        minuto e lasciava **89,25 EUR non fatturati**, e il tetto di 120 minuti valeva
        **120 sessioni di qualunque durata**. *Si vendeva un'unità e se ne misurava
        un'altra.*
        
        Il consuntivo lo calcola `videochat.consuntivo` dal **registro dei consumi**
        (l'apertura ha già la sua riga col `creato_il` e i due tenant): nessuna tabella
        nuova, nessuna migrazione. L'apertura resta un **acconto**, qui si addebita la
        differenza, e la seconda chiamata non addebita niente — `vc:<s>:chiusa` è la
        ricevuta.
        
        ⚠️ `soloPermesso: true` nel cancello, ed è la riga che va capita: un consuntivo
        **non è un acquisto**. Se il tetto lo rifiutasse, chi sfonda la quota pagherebbe
        **meno** di chi la rispetta, cioè D4 al contrario. Lo scope si verifica, il
        tetto no — e con questa opzione non si può consumare di più, solo **dichiarare**
        ciò che si è consumato.
        
        ⚠️ Il permesso è `videochat.apri`, non un permesso nuovo: chiudere una stanza
        **non è una capacità che si vende**, è l'altra metà dell'atto che si è già
        comprato. Un permesso nuovo vorrebbe uno scope nuovo, una voce di listino e
        quattro lingue, per una cosa che nessuno comprerebbe a parte.
      x-sorgente: "src/routes/v1/index.js:1167"
      x-permesso: "videochat.apri"
      x-freno: "preventivo"
      x-stati-dinamici: "stato"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "400":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/atelier/scheda":
    post:
      operationId: "postAtelierScheda"
      x-sorgente: "src/routes/v1/index.js:1226"
      x-permesso: "atelier.crea"
      x-freno: "preventivo"
      responses:
        "201":
          description: >-
            Creato.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "400":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/atelier/documento":
    post:
      operationId: "postAtelierDocumento"
      x-sorgente: "src/routes/v1/index.js:1242"
      x-permesso: "atelier.crea"
      x-freno: "preventivo"
      responses:
        "201":
          description: >-
            Creato.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "400":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/atelier":
    get:
      operationId: "getAtelier"
      x-sorgente: "src/routes/v1/index.js:1257"
      x-permesso: "atelier.leggi"
      x-freno: "navigazione"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/atelier/{id}":
    parameters:
      - name: id
        in: path
        required: true
        schema: { type: string }
    get:
      operationId: "getAtelierId"
      x-sorgente: "src/routes/v1/index.js:1287"
      x-permesso: "atelier.leggi"
      x-freno: "navigazione"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/agenda":
    post:
      operationId: "postAgenda"
      x-sorgente: "src/routes/v1/index.js:1304"
      x-permesso: "agenda.scrivi"
      x-freno: "preventivo"
      responses:
        "201":
          description: >-
            Creato.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "400":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
    get:
      operationId: "getAgenda"
      x-sorgente: "src/routes/v1/index.js:1342"
      x-permesso: "agenda.leggi"
      x-freno: "navigazione"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/agenda/{id}/stato":
    parameters:
      - name: id
        in: path
        required: true
        schema: { type: string }
    post:
      operationId: "postAgendaIdStato"
      x-sorgente: "src/routes/v1/index.js:1329"
      x-permesso: "agenda.scrivi"
      x-freno: "preventivo"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "400":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/calendario/aggregato":
    get:
      operationId: "getCalendarioAggregato"
      x-sorgente: "src/routes/v1/index.js:1366"
      x-permesso: "calendario.aggregato"
      x-freno: "navigazione"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "400":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/biblioteca":
    post:
      operationId: "postBiblioteca"
      x-sorgente: "src/routes/v1/index.js:1395"
      x-permesso: "biblioteca.assorbi"
      x-freno: "preventivo"
      x-stati-dinamici: "stato"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "201":
          description: >-
            Creato.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
    get:
      operationId: "getBiblioteca"
      x-sorgente: "src/routes/v1/index.js:1415"
      x-permesso: "biblioteca.cerca"
      x-freno: "navigazione"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/biblioteca/cerca":
    post:
      operationId: "postBibliotecaCerca"
      x-sorgente: "src/routes/v1/index.js:1425"
      x-permesso: "biblioteca.cerca"
      x-freno: "preventivo"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "400":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/biblioteca/{id}":
    parameters:
      - name: id
        in: path
        required: true
        schema: { type: string }
    delete:
      operationId: "deleteBibliotecaId"
      x-sorgente: "src/routes/v1/index.js:1438"
      x-permesso: "biblioteca.assorbi"
      x-freno: "preventivo"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/conoscenza":
    post:
      operationId: "postConoscenza"
      x-sorgente: "src/routes/v1/index.js:1503"
      x-permesso: "conoscenza.scrivi"
      x-freno: "preventivo"
      x-stati-dinamici: "statoDi(err.codice"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "201":
          description: >-
            Creato.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
    get:
      operationId: "getConoscenza"
      x-sorgente: "src/routes/v1/index.js:1531"
      x-permesso: "conoscenza.leggi"
      x-freno: "navigazione"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/conoscenza/{id}/certifica":
    parameters:
      - name: id
        in: path
        required: true
        schema: { type: string }
    post:
      operationId: "postConoscenzaIdCertifica"
      x-sorgente: "src/routes/v1/index.js:1541"
      x-permesso: "conoscenza.scrivi"
      x-freno: "preventivo"
      x-stati-dinamici: "statoDi(err.codice"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/conoscenza/{id}/revoca":
    parameters:
      - name: id
        in: path
        required: true
        schema: { type: string }
    post:
      operationId: "postConoscenzaIdRevoca"
      x-sorgente: "src/routes/v1/index.js:1563"
      x-permesso: "conoscenza.scrivi"
      x-freno: "preventivo"
      x-stati-dinamici: "statoDi(err.codice"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/conoscenza/{id}":
    parameters:
      - name: id
        in: path
        required: true
        schema: { type: string }
    delete:
      operationId: "deleteConoscenzaId"
      x-sorgente: "src/routes/v1/index.js:1580"
      x-permesso: "conoscenza.scrivi"
      x-freno: "preventivo"
      x-stati-dinamici: "statoDi(err.codice"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/conoscenza/cerca":
    post:
      operationId: "postConoscenzaCerca"
      description: |-
        Che cosa la persona SA su una domanda, senza farla parlare. E' la rotta con
        cui il cliente capisce **perche'** la sua persona ha rifiutato: vede i brani,
        i punteggi e la soglia, invece di dover indovinare.
      x-sorgente: "src/routes/v1/index.js:1600"
      x-permesso: "conoscenza.leggi"
      x-freno: "preventivo"
      x-stati-dinamici: "statoDi(err.codice"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/conoscenza/url":
    post:
      operationId: "postConoscenzaUrl"
      description: |-
        CARICA UNA FONTE DA URL: il server va a leggere un indirizzo scelto dal
        CLIENTE, e quella frase è tutto il problema.
        
        Il cancello sta in `lib/indirizzo-pubblico.js`: solo `https`, solo porte del
        web, nessuna credenziale nell'URL, e **tutti** gli indirizzi in cui il nome
        risolve devono essere pubblici — loopback, reti private e indirizzi dei
        metadati cloud sono rifiutati, con qualunque nome arrivino. I salti si
        seguono a mano e **ogni salto si rigiudica**: un indirizzo pubblico che
        risponde `302` verso `127.0.0.1` è il modo standard di passare un controllo
        fatto una volta sola. Poi il tipo di contenuto è un elenco chiuso e i byte
        si contano leggendo.
        
        Il rifiuto **dice il motivo** (`indirizzo_non_ammesso` col blocco che ha
        fermato la richiesta): un cliente che sbaglia URL ha diritto di capire, e
        nessuno di questi motivi rivela qualcosa che non si sappia già — che
        `127.0.0.1` sia loopback non è un segreto.
      x-sorgente: "src/routes/v1/index.js:1653"
      x-permesso: "conoscenza.scrivi"
      x-freno: "preventivo"
      x-stati-dinamici: "stato"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "201":
          description: >-
            Creato.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/conoscenza/reindicizza":
    post:
      operationId: "postConoscenzaReindicizza"
      description: |-
        RIFA' L'INDICE della conoscenza della persona.
        
        Serve in due casi veri, e da nessuno dei due c'era modo di uscire:
         · l'indicizzazione al caricamento e' **fallita** (il motore degli embedding
           non rispondeva): la fonte e' caricata, `indicizzazione` lo dichiara, e
           senza questa rotta l'unica strada era ricaricare il documento — che
           peraltro verrebbe rifiutato come `contenuto_gia_presente`;
         · il **modello** degli embedding e' cambiato: i vettori vecchi sono numeri
           prodotti da un altro modello, e confrontarli con il nuovo non significa
           niente. Si rifanno.
        Idempotente: calcola solo i brani che il vettore non l'hanno per il modello
        in corso, quindi su una conoscenza gia' indicizzata costa una query e torna
        zero.
      x-sorgente: "src/routes/v1/index.js:1690"
      x-permesso: "conoscenza.scrivi"
      x-freno: "preventivo"
      x-stati-dinamici: "statoDi(err.codice"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
        "503":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
  "/conoscenza/verdetti":
    get:
      operationId: "getConoscenzaVerdetti"
      description: |-
        Il referto del firewall: quanti NO, quanti SI, e per quale motivo.
      x-sorgente: "src/routes/v1/index.js:1711"
      x-permesso: "conoscenza.leggi"
      x-freno: "navigazione"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/mani/opera":
    post:
      operationId: "postManiOpera"
      x-sorgente: "src/routes/v1/index.js:1733"
      x-permesso: "mani.opera"
      x-freno: "preventivo"
      x-stati-dinamici: "stato"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/persone":
    post:
      operationId: "postPersone"
      description: |-
        CREARE UNA PERSONA VIA API (29/9/2026). Fino a oggi una persona nasceva solo
        da un ordine pagato nel negozio: agile-services, che ci usa come servizio,
        non aveva nessun modo di farne una. Le regole stanno in `services/forgia.js`
        e la piu' importante e' una: **si crea in `staging`, non in produzione**.
        Chi integra forgia e prova quanto vuole; quando una persona serve davvero,
        si compra. Il cancello commerciale e' li' dentro, non sparso qui.
        L'ORGANIZZAZIONE VIENE DALLA CHIAVE, mai dal corpo: se la prendessimo dal
        corpo, un cliente potrebbe creare una persona dentro l'organizzazione di un
        altro, e nei log sembrerebbe una richiesta normale.
      x-sorgente: "src/routes/v1/index.js:1796"
      x-permesso: "persone.crea"
      x-freno: "preventivo"
      x-stati-dinamici: "err.stato"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "201":
          description: >-
            Creato.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
    get:
      operationId: "getPersone"
      description: |-
        Le persone che questa organizzazione ha forgiato e non ancora comprato.
        
        La risposta e' limitata a `tetto` righe e dichiara la propria popolazione:
        `totale` quante persone l'organizzazione ha in questo stadio, `inQuestaPagina`
        quante ne porta questa risposta, `troncato` se il tetto ne ha tagliate altre.
      x-sorgente: "src/routes/v1/index.js:1862"
      x-permesso: "persona.descrivi"
      x-freno: "navigazione"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/persone/{agentKey}/promuovi":
    parameters:
      - name: agentKey
        in: path
        required: true
        schema: { type: string }
    post:
      operationId: "postPersoneAgentKeyPromuovi"
      description: |-
        PROMUOVE una persona forgiata: da «staging» a «produzione».
        
        E' il momento in cui il prodotto viene consegnato, quindi vuole un ordine
        **pagato** e della stessa organizzazione. Il cancello sta in
        `services/forgia.promuovi`, non qui: una regola commerciale sparsa fra le
        rotte e' una regola che prima o poi una rotta nuova si dimentica.
      x-sorgente: "src/routes/v1/index.js:1825"
      x-permesso: "persone.crea"
      x-freno: "preventivo"
      x-stati-dinamici: "err.stato"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/persone/{agentKey}/metodo":
    parameters:
      - name: agentKey
        in: path
        required: true
        schema: { type: string }
    get:
      operationId: "getPersoneAgentKeyMetodo"
      description: |-
        LA CHECKLIST DI NASCITA: i 6 pezzi del metodo su questa persona.
        
        Perche' e' una ROTTA e non solo un controllo interno: lo standard dice che
        i sei pezzi sono **obbligatori**, e una persona forgiata via API ne ha zero
        il giorno che nasce. Finche' questa risposta non esisteva, chi integra
        scopriva che cosa mancava dalla qualita' delle risposte della persona —
        cioe' dal cliente finale.
        
        Permesso `persona.descrivi` come l'elenco: dice che cosa la persona HA, non
        le sue istruzioni. I valori dei vincoli non escono da qui, solo le chiavi di
        primo livello: sapere che la condotta c'e' non e' leggerla (D12).
        
        Non e' un cancello: non blocca niente. Il cancello commerciale resta uno
        solo ed e' l'ordine pagato.
      x-sorgente: "src/routes/v1/index.js:1909"
      x-permesso: "persona.descrivi"
      x-freno: "navigazione"
      x-stati-dinamici: "err.stato"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/persone/{agentKey}/profilo":
    parameters:
      - name: agentKey
        in: path
        required: true
        schema: { type: string }
    patch:
      operationId: "patchPersoneAgentKeyProfilo"
      description: |-
        CORREGGE l'identita' di una persona gia' nata: nome, ruolo, carattere,
        carattere della voce, caratteristiche.
        
        E' una PATCH e non una PUT perche' tocca solo i campi che il corpo nomina:
        chi vuole cambiare il ruolo non deve rimandare il `system_prompt` che non
        ha, e che rimandandolo vuoto cancellerebbe. Un campo che non si sa
        modificare — `stadio`, `org_tenant_id` — si **rifiuta** con 400 invece di
        essere scartato: chi lo manda e riceve 200 crede di averlo cambiato.
        
        Lo `stadio` resta fuori: si muove solo con `/promuovi`, e il cancello e'
        l'ordine pagato. `agent_key` e `slug` non seguono il nome, ed e' voluto:
        sono l'indirizzo che il cliente ha gia' cablato.
      x-sorgente: "src/routes/v1/index.js:1937"
      x-permesso: "persone.profilo"
      x-freno: "preventivo"
      x-stati-dinamici: "err.stato"
      # lo stato lo decide il servizio, non questa rotta: qui si dice
      # da quale espressione viene, non che numero uscirà.
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/capacita":
    get:
      operationId: "getCapacita"
      description: |-
        IL CATALOGO, COME LO VEDE QUESTA PERSONA. È la prima chiamata che fa chi
        integra: dice quali capacità ha, su quali canali, e **l'elenco chiuso degli
        esiti** di ognuna — cioè il contratto, prima di scrivere lo `switch`.
      x-sorgente: "src/routes/v1/index.js:1993"
      x-permesso: "capacita.leggi"
      x-freno: "navigazione"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/canale/arrivo":
    post:
      operationId: "postCanaleArrivo"
      description: |-
        `channel_reply` — IL CAMPANELLO DEL TRASPORTO.
        
        Questa è la rotta che **AgileChannels** chiama quando un messaggio arriva:
        `webhook_endpoint`/`webhook_delivery` esistono nel suo schema (migrazione
        002) e il suo contratto dichiara il ciclo `x-non-ancora-servita`. Finché
        quel ciclo non c'è, la rotta la può chiamare chi ha la chiave della persona —
        ed è la stessa rotta, con lo stesso corpo, che il trasporto userà: così il
        giorno che il campanello nasce non cambia niente da questo lato.
        
        ⚠️ **`destinatario` non è decorativo**: è l'indirizzo NOSTRO su cui il
        messaggio è arrivato, e il cancello «è mio?» ci si appoggia. Senza, il primo
        arrivo su un numero condiviso lo prende chiunque.
      x-sorgente: "src/routes/v1/index.js:2035"
      x-permesso: "canale.rispondi"
      x-freno: "preventivo"
      responses:
        "400":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/canale/scrivi":
    post:
      operationId: "postCanaleScrivi"
      description: |-
        `channel_initiate` — scrive per prima. La chiave logica la decide chi chiede.
        
        🟢 DAL 24/10/2026 QUESTA ROTTA PORTA ANCHE IL CONTENUTO PREAPPROVATO (PS4). `modello`
        (`{ nome, variabili, lingua }`) e `template` (`{ nome, parametri, lingua }`) arrivano fin qui
        e scendono fino al Postino, che li valida e che sa a chi appartiene la WABA su cui quel testo
        e' approvato (A683). Prima di oggi il cancello `corpo_libero` rifiutava WhatsApp **in blocco**
        chiedendo un modello che non c'era nessun modo di passare: *una rotta che non accetta il campo
        che il suo rifiuto nomina chiude una strada a chiave e consegna il cartello, non la chiave.*
        ⚠️ I due campi NON si validano qui: la forma la rifiuta `contenutoPreapprovato` nel Postino
        (otto rifiuti, un nome pubblico solo + `dettaglio.postino`), e duplicare quelle regole qui
        vorrebbe dire tenerne due copie.
      x-sorgente: "src/routes/v1/index.js:2073"
      x-permesso: "canale.scrivi"
      x-freno: "preventivo"
      responses:
        "400":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/canale/passa-a-umano":
    post:
      operationId: "postCanalePassaaumano"
      description: |-
        `channel_handoff` — passa a un umano. Il referente lo dice il forge.
      x-sorgente: "src/routes/v1/index.js:2096"
      x-permesso: "canale.passa"
      x-freno: "preventivo"
      responses:
        "400":
          description: >-
            Risposta prevista dal codice di questa rotta.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/canale/consegna/{id}":
    parameters:
      - name: id
        in: path
        required: true
        schema: { type: string }
    get:
      operationId: "getCanaleConsegnaId"
      description: |-
        LO STATO DI UNA CONSEGNA. Chiude il giro della capacità: `channel_reply`
        torna `risposto` quando il trasporto ha **accodato**, e accodato non è
        consegnato — dirlo altrimenti sarebbe la bugia da cui nascono i messaggi
        persi. Chi integra passa l'`uscita_uid` che gli è tornato e legge lo stato
        vero dal Postino (`GET /v1/messages/{id}` di AgileChannels).
        
        Non c'era, e la funzione che la serve (`postino.statoDi`) era **un pezzo che
        nessuno chiamava**: l'ha trovata la guardia «chi lo chiama?» del negozio, non
        io. O si collegava o si toglieva; si collega, perché «è partita davvero?» è
        la domanda che il cliente fa subito dopo.
        
        ⚠️ LO STATO LO LEGGE **LA CHIAVE CHE HA SPEDITO**, e nessun'altra (A707, 24/10/2026).
        Il codice d'invio di un altro — di un altro cliente, o di un'altra persona dello stesso
        cliente — risponde **404 `MESSAGGIO_ASSENTE`**, lo stesso identico corpo del codice che non
        esiste: una risposta che distinguesse i due casi direbbe a chi domanda che il messaggio
        esiste ed è di qualcun altro. Chi integra con più persone usa, per domandare, la chiave con
        cui ha spedito.
      x-sorgente: "src/routes/v1/index.js:2148"
      x-permesso: "capacita.leggi"
      x-freno: "navigazione"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Risposta prevista dal codice di questa rotta.
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
  "/canale/fermati":
    post:
      operationId: "postCanaleFermati"
      x-sorgente: "src/routes/v1/index.js:2212"
      x-permesso: "capacita.leggi"
      x-freno: "preventivo"
      responses:
        "200":
          description: >-
            Riuscita.
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "401": { $ref: "#/components/responses/ChiaveNonValida" }
        "402":
          description: >-
            Rifiutata prima della rotta: quota_non_acquistata (src/services/persona.js:573) · quota_non_acquistata (src/services/persona.js:575).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "403":
          description: >-
            Rifiutata prima della rotta: scope_mancante (src/services/persona.js:515) · vietato_dal_profilo (src/services/persona.js:566).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "404":
          description: >-
            Rifiutata prima della rotta: persona_non_trovata (src/services/persona.js:371).
            Rifiutata prima della rotta: operazione_sconosciuta (src/services/persona.js:509).
            La forma del corpo non è dichiarata nel codice e qui
            non si inventa: vedi x-sorgente per la riga esatta.
        "423": { $ref: "#/components/responses/ChiaveGiustaMaBloccata" }
        "429": { $ref: "#/components/responses/QuotaEsaurita" }
