> ## Documentation Index
> Fetch the complete documentation index at: https://docs.befailproof.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Risoluzione dei problemi

> Documentazione per la risoluzione dei problemi di AgentEye.

Questa guida associa i sintomi che è più probabile riscontrare in produzione a una diagnosi concreta e a una soluzione, in modo che tu possa risolvere gli incidenti usando gli strumenti che già possiedi, senza dover implementare infrastrutture di osservabilità aggiuntive. Copre il server, il collector, il dashboard, l'assistente AI, Python SDK, il monitoraggio della salute e dei certificati, i backup, le analitiche supportate da ClickHouse e il multi-tenancy.

Le pagine del dashboard hanno ambito dell'organizzazione sotto `/<org-slug>/…`, e lo stream degli eventi è la home dell'organizzazione (`/<org-slug>/`). I nomi delle pagine in questa guida (ad esempio `/sessions`, `/queries`) si riferiscono a questi percorsi con ambito organizzativo.

***

## Visualizzazione dei log

AgentEye non include uno stack di logging o monitoring. Sia il server che il dashboard scrivono log strutturati su **stdout**, quindi puoi leggerli direttamente con `kubectl` o `docker`; non è richiesto alcun aggregatore.

### Kubernetes

Segui i log live per il server e il dashboard:

```bash theme={null}
kubectl logs -n agenteye -l app=server    -f --timestamps
kubectl logs -n agenteye -l app=dashboard -f --timestamps
```

Varianti utili:

| Obiettivo                                    | Comando                                                           |
| -------------------------------------------- | ----------------------------------------------------------------- |
| Ultime 200 righe (senza follow)              | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps`  |
| Log dal crash precedente                     | `kubectl logs -n agenteye <pod-name> --previous`                  |
| Traccia tutte le repliche contemporaneamente | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` |
| Postgres (StatefulSet)                       | `kubectl logs -n agenteye postgres-0 -f`                          |

### Docker Compose

```bash theme={null}
docker logs -f agenteye-server
docker logs -f agenteye-dashboard
```

### Correlazione di una singola richiesta tra dashboard e server

Ogni richiesta del dashboard è etichettata con un `request_id` e propagata al server tramite l'intestazione `x-request-id`. Il server lo ripete nelle sue intestazioni di risposta e in ogni riga di log che emette per quella richiesta. Per tracciare una richiesta end-to-end:

1. Cattura l'id dall'intestazione di risposta, ad esempio:
   ```bash theme={null}
   curl -i https://dashboard.example.com/api/events | grep -i x-request-id
   # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a
   ```
2. Esegui grep nei log di entrambi i pod per quell'id:
   ```bash theme={null}
   REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a
   kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ"
   kubectl logs -n agenteye -l app=server    --tail=5000 | grep "$REQ"
   ```

Vedrai le righe `proxy passthrough`, `withAuth: authorized` e `upstream response` del dashboard insieme alla coppia `http request received` / `http request completed` del server, condividendo tutte lo stesso `request_id`.

### Log JSON e `jq`

Imposta `AE_LOG_JSON=1` sul dashboard (è attivato per impostazione predefinita quando `NODE_ENV=production`) per emettere un oggetto JSON per riga. Quindi filtra strutturalmente:

```bash theme={null}
kubectl logs -n agenteye -l app=dashboard --tail=5000 \
  | jq 'select(.level == "warn" or .level == "error")'

kubectl logs -n agenteye -l app=dashboard --tail=5000 \
  | jq 'select(.route == "POST /api/keys")'
```

Il server Rust emette coppie di traccia `key=value` che grep funziona bene senza `jq`:

```bash theme={null}
kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5'   # 5xx
kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id='
```

### Aumento della verbosità

| Componente | Variabile d'ambiente | Esempio                                                  |
| ---------- | -------------------- | -------------------------------------------------------- |
| Server     | `RUST_LOG`           | `RUST_LOG=debug` o `RUST_LOG=agenteye_server=debug,info` |
| Dashboard  | `AE_LOG_LEVEL`       | `AE_LOG_LEVEL=debug`                                     |

`debug` sul server aggiunge una riga `api key authenticated` per auth. `debug` sul dashboard aggiunge righe `upstream request`, `session validated` e `proxy passthrough`.

### Conservazione dei log

Lo stdout del contenitore è effimero; kubelet ruota i file di log (default \~10 MiB per contenitore) e ne mantiene un numero ridotto su disco. Una volta eliminato un pod i log sono spariti. Se hai bisogno di una conservazione più lunga o di una ricerca cross-pod, punta il tuo cluster a un collector di log (Loki, CloudWatch, Cloud Logging, Datadog, ecc.) che traccia `/var/log/containers/`. AgentEye non richiede o prescrive alcuna scelta specifica.

***

## Problemi di autenticazione

### `docker pull` fallisce con "unauthorized"

Assicurati di aver autenticato Docker su GHCR con il tuo `AGENTEYE_TOKEN`:

```bash theme={null}
echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin
```

Il token deve avere permesso `read:packages` sull'org `agenteye-enterprise`. Contatta `support@exosphere.host` se il tuo token non funziona.

### `gh release download` restituisce 404 o 401

* Conferma che `AGENTEYE_TOKEN` è esportato nella tua shell: `echo $AGENTEYE_TOKEN`
* Conferma che stai usando `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` (la CLI `gh` legge `GITHUB_TOKEN`)
* Il token ha bisogno di `contents:read` su `agenteye-enterprise/releases`

***

## Problemi del server

### Il server fallisce con "invalid port number"

La `POSTGRES_PASSWORD` (o un'altra credenziale) contiene caratteri speciali URL (`/`, `+`, `=`) che interrompono l'analisi di `DATABASE_URL`. Rigenera la password utilizzando la codifica hex:

```bash theme={null}
NEW_PASS=$(openssl rand -hex 24)
```

Quindi aggiorna il secret Kubernetes e la password all'interno di Postgres (o ricrea il `.env` per Docker Compose), e riavvia il server. Vedi i passaggi completi in [enterprise-docs/kubernetes-deployment.md](/it/agenteye/kubernetes-deployment) § "PostgreSQL credentials".

### Il server esce immediatamente all'avvio

Controlla i log del contenitore:

```bash theme={null}
docker logs agenteye-server
```

Cause comuni:

* `DATABASE_URL` non impostato o malformato: il server registrerà l'errore e uscirà.
* Postgres non è raggiungibile: conferma che il contenitore Postgres o il DB gestito è in esecuzione e che host/porta sono corretti.
* Le migrazioni sono fallite: controlla i log per errori SQL.

### `GET /health` restituisce non-200 o timeout

Il server potrebbe ancora eseguire le migrazioni al primo avvio. Attendi alcuni secondi e riprova:

```bash theme={null}
curl http://localhost:8080/health
```

Se il problema persiste, controlla `docker logs agenteye-server` per gli errori.

### `GET /ready` restituisce 503

`/ready` è il probe di readiness: restituisce `503` quando il server non riesce a raggiungere **Postgres o ClickHouse**. Il corpo nomina la dipendenza non funzionante:

```bash theme={null}
curl -s http://localhost:8080/ready
# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}}
```

Correggi qualunque dipendenza riporta come `down`: il pod ClickHouse/Postgres è `Running`? `CLICKHOUSE_URL` / `DATABASE_URL` è corretto e raggiungibile? Su Kubernetes il pod legge `NotReady` finché `/ready` non si recupera; è previsto ed è esattamente il segnale su cui gli alert di monitoraggio della salute si basano. Redis non è mai una causa: è riportato ma non fa fallire la readiness.

### Il collector restituisce 401 Unauthorized

La chiave API del collector non ha l'autorizzazione `events:add`, oppure la chiave è stata disabilitata. Crea una nuova chiave con il permesso corretto:

```bash theme={null}
curl -s -X POST http://your-server:8080/keys \
  -H "Authorization: Bearer $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"new-collector","permissions":["events:add"]}'
```

### Le richieste autenticate sono improvvisamente diventate lente (\~200ms invece di \~5ms)

Questo è il sintomo di Redis che è inattivo mentre `REDIS_URL` è impostato. Ogni chiamata cache timeout dopo 100ms e poi fallisce in Postgres; sui percorsi auth e OTP la richiesta effettua due tali fallimenti.

Conferma nei log del server:

```
auth cache: L2 get failed error=redis call timed out
```

Risoluzione:

1. `redis-cli -h <your-redis> ping` per confermare che Redis è raggiungibile sulla rete del cluster.
2. Se Redis era brevemente inattivo ed è ora di nuovo disponibile, **riavvia i pod del server**. `redis::aio::ConnectionManager` non ristabilisce in modo affidabile dopo che la connessione sottostante si interrompe; un riavvio del pod raccoglie la nuova connessione in modo pulito. Lo stesso vale per il dashboard.
3. Se non vuoi eseguire Redis in questo momento, cancella `REDIS_URL` nell'implementazione e riavvia. Entrambi i servizi funzionano senza la cache (la correttezza è conservata; la latenza ritorna alla baseline pre-Redis).

### Il server riporta `OTP request rate-limited` nei log ma l'utente dice che ha provato solo una volta

Controlla se Redis era irraggiungibile. Il percorso di fallback utilizza `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`, che vede le righe OTP precedentemente generate. Se l'utente è stato a fare clic ripetuto su "Resend" per un'ora, la finestra di 15 minuti potrebbe ancora contenere ≥5 codici. Risolvi aspettando che la finestra scorra o eseguendo `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (console dell'operatore).

### Ho cambiato `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` e riavviato; nulla è cambiato

Queste variabili d'ambiente sono **seed del primo avvio solo**. Una volta che la tabella `settings` ha una riga per la chiave corrispondente, quella riga è la fonte di verità; la variabile d'ambiente viene letta una volta al primo avvio e quindi ignorata in ogni riavvio successivo.

Per cambiarli dopo il primo avvio, accedi al dashboard e modificali in `/settings`. Il cambiamento si applica entro pochi secondi su tutte le repliche; nessun riavvio richiesto.

Se hai bisogno di forzare un re-seed da env (raro, tipicamente utile solo in sviluppo), esegui `DELETE FROM settings WHERE key = '<key>'` e riavvia il server. Il bootstrap raccoglierà il valore della variabile d'ambiente corrente al prossimo avvio. La modifica tramite `/settings` è il percorso supportato in produzione.

***

## Problemi del collector

### Il collector si avvia ma gli eventi non appaiono nel dashboard

1. Conferma che il collector è in esecuzione: `systemctl status agenteye-collector` (Linux) o controlla il processo.
2. Conferma che `AGENTEYE_URL` punta a `http(s)://your-server-host:8080/events` (nota: percorso `/events`).
3. Esegui un flusso una tantum per vedere l'output immediato:
   ```bash theme={null}
   agenteye-collector flush
   ```
4. Controlla che Python SDK stia effettivamente scrivendo file: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/`
5. Se esistono file in `${AGENTEYE_HOME:-~/.agenteye}/failed/`, i caricamenti stanno fallendo. Controlla i log del collector per l'errore, probabilmente un 4xx (chiave o URL errato) o un problema di rete.

### I file si stanno accumulando in `$AGENTEYE_HOME/events/` e non vengono caricati

* Il collector potrebbe non essere in esecuzione. Avvialo: `agenteye-collector start`; scarica automaticamente gli eventi preesistenti all'avvio.
* Controlla la salute del collector: `agenteye-collector health`
* Il collector potrebbe essere in esecuzione ma non riuscire a raggiungere il server. Controlla le regole firewall tra gli host collector e server.

### File in `$AGENTEYE_HOME/failed/`

I file si spostano in `failed/` dopo che tutti i tentativi di ripetizione sono esauriti (predefinito: 5 tentativi con backoff esponenziale). Ciò significa che:

* Il server ha restituito un errore 4xx (chiave errata, URL sbagliato o problema di payload)
* Il server era irraggiungibile per l'intera finestra di ripetizione

Correggi il problema sottostante, quindi ricoda manualmente:

```bash theme={null}
mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/
agenteye-collector flush
```

### Il collector riporta `network error` su ogni caricamento (handshake TLS fallisce)

Se `curl -k` contro `AGENTEYE_URL` ha successo ma il file binario del collector fallisce ogni caricamento con `error sending request for url (...)`, il server AgentEye sta presentando un certificato TLS che non è firmato da una CA pubblicamente attendibile.

Il **percorso di produzione** è il nome host di ingestion ACME configurato in `deploy/base/certificates/domain.env` (vedi [`kubernetes-deployment.md`](/it/agenteye/kubernetes-deployment) Fase 3.1 / 4.2). Una volta che `INGEST_DOMAIN` si risolve verso il public Traefik LB e cert-manager ha emesso il certificato Let's Encrypt, i collector verificano il certificato del server rispetto all'archivio di fiducia del sistema **senza `AGENTEYE_TLS_CA` necessario**; cancellalo dalla configurazione del collector se era impostato rispetto a un'implementazione autofirmata più vecchia.

**Sintomo: il collector ha funzionato ieri, fallisce oggi dopo un intervallo di \~90 giorni.** Ciò significa che l'implementazione è ancora sull'issuer `selfsigned` legacy per `ingest-tls`. Il certificato di 90 giorni ha ruotato e il file CA ancorato è obsoleto. Correggi permanentemente passando il cluster all'issuer ACME (Fase 3.1 della guida di implementazione). Sblocco a breve termine: estrai nuovamente il certificato del server corrente e aggiorna `AGENTEYE_TLS_CA`:

```bash theme={null}
kubectl get secret ingest-tls-cert -n agenteye \
  -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt
```

```bash theme={null}
export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt
agenteye-collector flush
```

`AGENTEYE_TLS_CA` aggiunge un ancoraggio di fiducia aggiuntivo; le radici pubbliche standard sono ancora attendibili.

### Il certificato `ingest-tls` è bloccato con `Ready: False` dopo la distribuzione

```bash theme={null}
kubectl describe certificate ingest-tls -n agenteye
```

Guarda gli `Events` e l'`Order` / `Challenge` a cui si fa riferimento. Cause comuni:

* **DNS non risolve verso il public LB.** Il validatore HTTP-01 non riesce a raggiungere `INGEST_DOMAIN`. Verifica con `dig +short INGEST_DOMAIN`; dovrebbe risolvere allo stesso indirizzo del `EXTERNAL-IP` del LoadBalancer `traefik-public`. cert-manager ritenta automaticamente una volta propagato il DNS; non è necessario eliminare il certificato.
* **Porta 80 bloccata al load balancer / security group.** HTTP-01 richiede che la porta 80 sia raggiungibile dai validatori pubblici di Let's Encrypt. Se hai un WAF a monte o SG che limita `:80`, aprilo (la configurazione di Traefik reindirizza a HTTPS, ma Boulder segue il reindirizzamento e accetta la risposta).
* **`dnsNames` non sostituito.** Se `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` mostra `INGEST_DOMAIN_PLACEHOLDER`, hai saltato il passaggio `domain.env`; crealo da `domain.env.example` e riapplica.
* **Rate limited da Let's Encrypt.** Gli ordini ripetuti non riusciti per lo stesso nome host attivano i limiti di certificato duplicato o convalida non riuscita. Attendi almeno un'ora prima di riprovare; controlla lo stato dell'ordine per il messaggio di rate-limit esatto.

### Il certificato `dashboard-tls` è bloccato con `Ready: False` / il browser mostra ancora un avviso

Lo stesso flusso di diagnosi di `ingest-tls` sopra (`kubectl describe certificate dashboard-tls -n agenteye`); le cause DNS, porta-80, placeholder e rate-limit si applicano tutte, più due specifiche del dashboard:

* **`DASHBOARD_DOMAIN` risolve al LoadBalancer sbagliato.** Deve puntare al LB Traefik del *dashboard*, non a quello di ingestion pubblico. Esegui `dig +short` sul nome host e confronta con l'indirizzo del LB del dashboard.
* **L'istanza Traefik del dashboard non può servire la sfida.** Deve essere installata con il file di valori del dashboard bundle, che abilita un provider Ingress con ambito per il risolutore HTTP-01 di cert-manager. Senza di esso il risolutore non è instradabile e l'ordine rimane `pending` per sempre. Aggiorna l'istanza con i valori forniti; la sfida pendente si completa quindi da sola.
* **Il LoadBalancer era limitato IP.** I range di origine si applicano anche alla porta 80, il che blocca i validatori di Let's Encrypt — sia il primo rilascio che ogni rinnovo di \~75 giorni. Riapri il LB, o coordina un risolutore DNS-01 con il supporto prima di bloccarlo.

Durante il fallimento dell'emissione, il dashboard continua a servire il suo certificato precedente (o il valore predefinito dell'ingress su un'installazione nuova) — l'accesso è degradato da un avviso del browser, mai inattivo.

### La CLI continua a saltare la verifica TLS dopo che il dashboard ha ottenuto un certificato attendibile

`--insecure` è persistito su `cli.json` al login. Una volta che il dashboard serve un certificato pubblicamente attendibile, accedi di nuovo con `agenteye --base-url https://<your-dashboard-domain> --secure login`; la verifica viene salvata di nuovo e l'avviso di avvio scompare.

***

## Problemi del dashboard

### Impossibile disabilitare o modificare l'utente `ADMIN_EMAIL`

Per progettazione. L'utente che corrisponde a `ADMIN_EMAIL` è contrassegnato come protetto ad ogni avvio del server: il dashboard nasconde il pulsante Disabilita per quella riga e l'API rifiuta `DELETE /users/:id` e `PUT /users/:id` contro di essa con `403 Forbidden`. Un trigger del database rifiuta anche istruzioni `UPDATE` dirette che disabiliterebbero la riga protetta.

Per ruotare l'admin di bootstrap, cambia `ADMIN_EMAIL` nel tuo ambiente e riavvia il server. Il nuovo email è upsertato come protetto. L'admin precedente mantiene il flag protetto fino a quando non viene cancellato nel database (tipicamente va bene, poiché l'email precedente è comunque un admin valido fino a quando non lo rimuovi esplicitamente).

### Il dashboard non mostra eventi

1. Conferma che l'URL del server e la chiave API sono corretti nelle variabili d'ambiente del dashboard (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`).
2. La chiave API del dashboard ha bisogno dell'autorizzazione `events:read`.
3. Conferma che gli eventi sono stati effettivamente acquisiti: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"`

### `/errors` è vuoto ma `/events` mostra righe rosse

Le versioni più recenti di SDK emettono guasti come eventi `agent_end` / `tool_result` / `hook_completed` con `outcome: "error"` nel payload, anziché come una riga `event_type: "error"` dedicata. La pagina `/errors` ora corrisponde a entrambi: qualsiasi riga che il flusso `/events` pinta di rosso (esplicito `event_type='error'`, payload `outcome`/`status` nell'insieme di guasto, `is_error: true`, o un campo `error` veritiero) appare su `/errors`. Se in precedenza hai visto "nessun errore in questa finestra" mentre le righe rosse erano visibili su `/events`, aggiorna il dashboard + server insieme (il filtro ampliato è `errored=true` su `GET /events`) e le due viste saranno d'accordo.

### `/models`, `/tools` o `/hooks` è lento o non riesce a caricare su ampi intervalli di tempo

**Sintomo:** su una grande tabella di eventi (milioni di righe), l'apertura di `/models`, `/tools` o `/hooks` — o l'ampliamento dell'intervallo di tempo a `7d`, `30d` o `all` — i grafici girano e poi mostrano un errore di caricamento. Il server registra un ClickHouse `MEMORY_LIMIT_EXCEEDED` (Codice 241) o un timeout della query per la richiesta `latency_aggregate`.

**Causa:** le build più vecchie calcolavano i rollup di latenza e distribuzione di queste pagine con una query che leggeva il `payload` dell'evento grezzo completo e associava gli eventi di richiesta/risposta con un'ordinazione e un join in memoria. Il picco di memoria della query quindi cresceva con la dimensione della finestra, quindi su un tenant occupato un'ampia gamma potrebbe superare il ceiling di memoria per query di ClickHouse.

**Correzione:** aggiorna a una build che include questa correzione. Il rollup ora legge solo le colonne promosse compatte e associa gli eventi con un'aggregazione di streaming, quindi il picco di memoria non scala più con il payload grezzo — le finestre larghe rimangono ben all'interno del ceiling di memoria e vengono restituite in una frazione del tempo. Il miglioramento è interamente lato query: si applica a tutti i dati esistenti al successivo caricamento della pagina, senza ricoingestione o backfill.

### Il dashboard non riesce a caricare / pagina vuota

Controlla i log del contenitore del dashboard:

```bash theme={null}
docker logs agenteye-dashboard
```

La causa più comune è che `AGENTEYE_SERVER_URL` o `AGENTEYE_API_KEY` manchi o punti a un server irraggiungibile.

### Analitiche/telemetria del dashboard

Il dashboard invia analitiche sull'utilizzo dei prodotti anonime a PostHog per impostazione predefinita, instradate tramite il percorso `/ingest` del dashboard stesso (un proxy inverso a `https://us.i.posthog.com`). L'invio in primo piano significa che i blocker di annunci del browser non li eliminano. Questo è indipendente dalla funzionalità principale del dashboard:

* Il **contenitore dashboard** (non il browser) è ciò che raggiunge PostHog. Se il suo accesso in uscita a `https://us.i.posthog.com` è bloccato, la telemetria silenziamente non-op; il dashboard funziona normalmente e nessun errore viene visualizzato agli utenti.
* Non vengono mai inclusi dati di agenti, sessioni o eventi, solo l'utilizzo dell'UI del dashboard.
* Per disabilitare la telemetria interamente, imposta `AE_ANALYTICS_DISABLED=1` sul contenitore del dashboard e riavvia. Vedi [Telemetria & privacy](/it/agenteye/deployment#telemetria--privacy) nella guida di distribuzione.

### Telemetria della CLI / telemetria

La CLI `agenteye` invia analitiche sull'utilizzo anonime a PostHog per impostazione predefinita: quali comandi vengono eseguiti, stato di successo/uscita e durata. Questo è indipendente dalla funzionalità della CLI:

* La **macchina che esegue la CLI** raggiunge direttamente `https://us.i.posthog.com`. Se il suo accesso in uscita è bloccato, la telemetria silenziamente non-op (l'invio è limitato nel tempo, quindi non ritarda mai un comando) e la CLI funziona normalmente.
* Non vengono mai inclusi dati di agenti, sessioni o eventi: gli **argomenti e i valori del flag** del comando (URL del dashboard, token, email, ID della sessione, filtri di query) non vengono mai inviati.
* Per disabilitarlo, imposta `AGENTEYE_ANALYTICS_DISABLED=1` (o il cross-tool `DO_NOT_TRACK=1`) nell'ambiente della CLI. Vedi [Telemetria & privacy](/it/agenteye/cli#telemetria--privacy) nella guida della CLI.

***

## Problemi dell'assistente AI

Vedi [enterprise-docs/assistant.md](/it/agenteye/assistant) per la configurazione completa.

### La bolla dell'assistente non appare

La bolla è nascosta a meno che **tutti** questi non siano veri:

* L'utente connesso ha l'autorizzazione `agent:use`.
* `AGENTEYE_AGENT_URL` è impostato sul dashboard e il servizio `agent` è raggiungibile.
* Un endpoint LLM è configurato sul servizio `agent` (`ANTHROPIC_API_KEY`, un gateway tramite `ANTHROPIC_BASE_URL`, o Bedrock/Vertex). Senza alcuno impostato, l'agente riporta "non configurato" e la bolla rimane nascosta.

Controlla la salute dell'agente dall'host del dashboard: `curl http://agent:9100/health` dovrebbe restituire `{"status":"ok","llm_configured":true,...}`.

### L'assistente dice che non può leggere qualcosa

Gli strumenti sono controllati per utente. Se un utente non dispone di `evaluations:read` (o `events:read`, `dashboards:read`), gli strumenti corrispondenti non vengono offerti e l'assistente dirà che non può leggere quei dati. Concedi il permesso di lettura pertinente.

### "assistente non configurato" (HTTP 503) durante l'invio

Il contenitore `agent` non ha un endpoint LLM configurato, oppure il `AGENTEYE_AGENT_TOKEN` del dashboard non corrisponde a quello dell'agente. Imposta entrambi e riavvia.

### Il contenitore `agent` si riavvia / OOM sotto carico

Ogni conversazione genera un processo figlio di breve durata. Assicurati che il contenitore venga eseguito con un processo init (l'immagine usa `tini`; in Compose imposta `init: true`) e dagli limiti di memoria adeguati. Riduci `AGENTEYE_AGENT_MAX_STEPS` se necessario.

***

## Problemi della CLI

### `agenteye` non riesce ad avviarsi con `ModuleNotFoundError: No module named 'click'`

Un'installazione nuova della CLI `agenteye` alla versione **0.1.6** può bloccarsi all'avvio con:

```
ModuleNotFoundError: No module named 'click'
```

0.1.6 si affidava a `click` per essere installato indirettamente da `typer`; i rilasci `typer` attuali non lo estraggono più, quindi un ambiente pulito finisce per mancare il pacchetto. **Aggiorna a 0.1.7 o versioni successive**, che dipendono da `click` direttamente:

```bash theme={null}
pipx upgrade agenteye      # se installato con pipx (o: pipx install --force agenteye)
uv tool upgrade agenteye   # se installato con uv
pip install --upgrade agenteye
```

Vedi [enterprise-docs/cli.md](/it/agenteye/cli) per la guida di installazione.

***

## Problemi di Python SDK

### Nessun file che appare in `$AGENTEYE_HOME/events/`

L'SDK memorizza nel buffer gli eventi e scarica ogni 500 ms per impostazione predefinita. Se il tuo processo esce prima dello scaricamento, gli eventi potrebbero andare persi. Chiama `agenteye.configure(flush_interval=0.1)` per uno scaricamento più veloce negli script di breve durata, o assicurati che il tuo processo sia in esecuzione abbastanza a lungo per un ciclo di scaricamento.

Se `AGENTEYE_HOME` è impostato, verifica che l'SDK stia scrivendo in `$AGENTEYE_HOME/events/` e non in `~/.agenteye/events/` (richiede SDK ≥ 0.0.1b5).

### `ValueError: Reserved field names cannot be used as custom fields`

I nomi `timestamp`, `type` e `environment` sono riservati e non possono essere usati come campi personalizzati. Passare uno qualsiasi di loro solleva:

```
ValueError: Reserved field names cannot be used as custom fields: [...]
```

Rinomina il campo personalizzato offensivo. Nota che `session_id` e `agent_id` sono parametri espliciti della chiamata dell'evento, non campi personalizzati; passare uno di essi nuovamente come campo personalizzato solleva `TypeError`.

***

## Problemi di monitoraggio della salute

### Nessun avviso in arrivo su Slack (Robusta)

L'avviso della salute di Robusta è **opt-in**; non invia nulla finché non è installato e puntato a un canale Slack. Verifica il rilascio e il suo sink:

```bash theme={null}
kubectl get pods -n robusta          # robusta-runner + robusta-forwarder dovrebbero essere Running
kubectl logs -n robusta -l app=robusta-runner --tail=50
```

Cause comuni: `api_key` / `slack_channel` di Slack non erano impostati (o il token è stato revocato); `api_key` è un token di relay cloud di Robusta (`robusta integrations slack`) ma il `disableCloudRouting: true` in bundle ha bisogno di un **bot token** Slack self-hosted (`xoxb-…`), o imposta `disableCloudRouting: false`; l'ambito del sink esclude lo spazio dei nomi in cui i tuoi pod vengono eseguiti (i valori in bundle hanno ambito `agenteye`); o ancora non c'è stata alcuna interruzione. Forza un avviso di test eliminando un pod:

```bash theme={null}
kubectl -n agenteye delete pod -l app=clickhouse   # verrà ricreato
```

Vedi [enterprise-docs/health-monitoring.md](/it/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) per l'installazione e la configurazione.

### Il server continua a fluttuare `NotReady`

Il probe di readiness colpisce `/ready`, che fallisce quando Postgres o ClickHouse è irraggiungibile. Se il server cicla dentro e fuori da `NotReady`, una dipendenza è intermittentemente non disponibile; controlla i pod di ClickHouse e Postgres e il `CLICKHOUSE_URL` / `DATABASE_URL` del server. Conferma cosa riporta `/ready`:

```bash theme={null}
kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready'
```

Questo probe è deliberatamente tollerante (un generoso threshold di fallimento), quindi la fluttuazione sostenuta indica un vero problema di dipendenza piuttosto che un probe troppo aggressivo. La liveness rimane su `/health`, quindi la fluttuazione della readiness **non** riavvierà il pod.

## Problemi di monitoraggio dei certificati

### CronJob non sta inviando notifiche Slack

`cert-renewal-check` CronJob richiede un URL webhook Slack archiviato in un Secret. Verifica che esista:

```bash theme={null}
kubectl get secret cert-renewal-notify-config -n agenteye
```

Se manca, crealo:

```bash theme={null}
kubectl create secret generic cert-renewal-notify-config \
  --namespace agenteye \
  --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
```

Senza il secret, CronJob continua a essere eseguito e registra i risultati su stdout. Controlla i log con:

```bash theme={null}
kubectl logs -n agenteye -l job-name --tail=50
```

### Il certificato client è scaduto prima che venisse ricevuta una notifica

CronJob viene eseguito ogni 12 ore. Se non è stato eseguito, controlla il suo stato:

```bash theme={null}
kubectl get cronjob cert-renewal-check -n agenteye
```

Attiva un controllo manuale:

```bash theme={null}
kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye
kubectl logs -n agenteye -l job-name=manual-cert-check
```

Per ri-emettere immediatamente il certificato scaduto:

```bash theme={null}
cd base/certificates/client-certs
./issue-client-cert.sh <cluster-name>
```

Quindi applica il `collector-mtls-secret.yaml` rigenerato nel cluster(i) che esegue i collector e riavviali:

```bash theme={null}
kubectl apply -f collector-mtls-secret.yaml -n <collector-namespace>
```

***

## Problemi di backup

### `agenteye-backup` fallisce con "No space left on device"

CronJob `agenteye-backup` scarica Postgres + ClickHouse in un `backup-tmp` volume scratch `emptyDir` (predefinito `30Gi`), quindi **effettua lo streaming** dell'archivio `tar` direttamente verso S3 — l'archivio compresso non viene mai riscritto sul scratch, quindi lo scratch deve solo contenere i *dump grezzi*, non dump + una seconda copia di archivio su disco. Un pod evitato / `No space left on device` significa quindi che i **dump grezzi** superano la dimensione del scratch (il dump `events` di ClickHouse domina e cresce nel tempo). Controlla i log del job non riuscito:

```bash theme={null}
kubectl logs -n agenteye -l job-name=<failed agenteye-backup job>
```

Correzione: nel tuo overlay, aumenta il `sizeLimit` dell'`emptyDir` del `backup-tmp` di CronJob sopra il totale del dump grezzo, e assicurati che il dispositivo di archiviazione effimera del nodo possa effettivamente contenerlo (`sizeLimit` è un cap, non una prenotazione). Se i dump superano il disco di un singolo nodo, sostituisci l'`emptyDir` con un PVC (EBS/PD) per `backup-tmp`, o comprimi i dump all'origine.

> Le versioni più vecchie scrivevano il `.tar.gz` nello *stesso* scratch `20Gi` dei dump, quindi `dump + archivio` lo ha superato e il pod è stato evitato **prima** che l'upload fosse eseguito — il che sembra un guasto S3 ma è veramente disco. Lo streaming dell'upload rimuove quel raddoppio.

### `agenteye-backup` fallisce installando `curl`

Il job viene eseguito sull'immagine `postgres:16` e installa `curl` all'avvio per il dump HTTP di ClickHouse. Su un cluster senza uscita verso i mirror del pacchetto Debian, il passaggio `apt-get` fallisce. Consenti quel egress dal pod di backup, o costruisci `curl` in un'immagine di backup personalizzata/con mirror e referenziala nel tuo overlay.

### `agenteye-backup` viene eseguito ma nulla arriva nell'object storage

La base spedisce un vero `BACKUP_BUCKET` (`ts-prod-agenteye/backups`) e il ServiceAccount `agenteye-backup`. Il job **effettua lo streaming** dell'archivio verso S3 (`tar cz … | aws s3 cp - s3://…`). Se il pod di backup non ha accesso in scrittura al bucket, l'upload fallisce — e poiché lo script viene eseguito in `set -euo pipefail`, un fallimento in qualsiasi punto del pipe **fallisce** l'intero job al passaggio `upload` piuttosto che silenziare non-op (il trap EXIT del pod registra `backup FAILED during step: upload`). Questo è anche il passaggio che raggiungi *dopo* aver corretto un'evizione di spazio scratch, quindi se i backup erano precedentemente evitati al passaggio di archivio, verifica che l'upload ora arriva. Grep il log del job non riuscito per l'errore di accesso S3:

```bash theme={null}
kubectl logs -n agenteye -l job-name=<failed agenteye-backup job> | grep -iE 's3|upload|denied'
```

Correzione: nel tuo overlay imposta `BACKUP_BUCKET` su un bucket che possiedi e annota il ServiceAccount `agenteye-backup` esistente con accesso in scrittura (IRSA / Workload Identity / Pod Identity). Vedi la sezione **Backups** di [enterprise-docs/kubernetes-deployment.md](/it/agenteye/kubernetes-deployment).

***

## Valutazioni supportate da ClickHouse / sessioni / query

### La barra laterale della pagina `/queries` è vuota dopo l'aggiornamento

Sono previste tre tabelle (`events`, `evaluations`, `agent_sessions`). Se la barra laterale SchemaBrowser è vuota dopo l'aggiornamento, il server non ha applicato il DDL di ClickHouse all'avvio. Controlla i log del server per `failed to apply CH DDL statement`:

```bash theme={null}
kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL'
```

La causa più comune è che ClickHouse non sia raggiungibile durante l'esecuzione delle migrazioni. Il server rifiuta di avviarsi se non riesce a raggiungere CH, quindi un pod bloccato di solito ha un `CrashLoopBackOff` piuttosto che una pagina di query silenziosamente interrotta, ma un'applicazione DDL parziale (un'istruzione OK, i prossimi 5xx) lascia lo schema mezzo-cotto. Riavvia il pod del server dopo che è stato verificato che CH è raggiungibile:

```bash theme={null}
kubectl rollout restart deploy/server -n agenteye
```

### Le nuove valutazioni non appaiono in `/sessions` o `/queries`

Dopo l'aggiornamento, le nuove valutazioni vengono scritte su ClickHouse, non su Postgres, e appaiono in `/sessions` (con gatekeeping su `evaluations:read`) e in `/queries`. Se non appaiono:

1. Conferma che la pipeline dell'evaluator sia abilitata (`EVALUATOR_ENDPOINT` impostato sul server) e stia producendo risultati terminali; controlla le righe `evaluation_finalized`.
2. Conferma che CH sia raggiungibile dal server: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`.
3. Spot-check la tabella CH: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`.

### Le query falliscono sotto carico con "Memory limit exceeded", oppure ClickHouse è `OOMKilled`

**Sintomo:** sotto carico pesante di dashboard/query, le pagine analitiche (lo stream di eventi, `/sessions`, la visualizzazione latenza/modelli, l'editor SQL) iniziano a fallire o timeout; il server brevemente fluttua `NotReady`; e il pod di ClickHouse mostra un conteggio di riavvio in aumento. Questo è quasi sempre **memoria**, non CPU o disco.

**Conferma che sia memoria** (non un problema di throughput che la replica risolverebbe):

1. Controlla il pod per kill da mancanza di memoria:
   ```bash theme={null}
   kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled'
   ```
   `Reason: OOMKilled` / `Exit Code: 137` con un conteggio di riavvio crescente è il contrassegno.

2. Chiedi a ClickHouse cosa sta rifiutando:
   ```bash theme={null}
   kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \
     "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC"
   ```
   Un grande conteggio di `MEMORY_LIMIT_EXCEEDED` è la firma. Il messaggio legge *"maximum: N GiB"* — quel **N è `0.9 × il limite di memoria del pod`** (il `max_server_memory_usage_to_ram_ratio` in `deploy/base/clickhouse/configmap.yaml`). Se le tue letture pesanti hanno bisogno di più di N, vengono rifiutate.

3. Escludi le cose che *non* sono il problema — se CPU, conteggio parti e disco sono tutto basso, aggiungere repliche/sharding sarebbe costo sprecato:
   ```bash theme={null}
   kubectl -n agenteye top pod clickhouse-0
   kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \
     "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table"
   ```

**Causa:** il limite di memoria del pod di ClickHouse è troppo piccolo per il set di lavoro analitico. Le letture più pesanti estraggono la colonna JSON `payload` grezza, eseguono `JSONExtract*` su di essa, e usano `FINAL` — ognuna può avere bisogno di diversi GiB. Se le cache configurate (`mark_cache_size` + `uncompressed_cache_size`) sono più grandi del pod, le compongono: le cache sono caricate contro lo stesso budget e affollano la memoria di query.

**Correzione — scala la memoria di ClickHouse:**

1. Aumenta il limite di memoria di ClickHouse nel tuo overlay patchando le `resources` del contenitore StatefulSet `clickhouse` (lo stesso meccanismo di overlay usato per le `resources` degli altri componenti). Il budget del server utilizzabile è `0.9 × limit`, quindi un limite `6Gi` dà \~5.4 GiB, `16Gi` dà \~14 GiB. Imposta anche `requests.memory` a un floor vero, quindi lo scheduler lo prenota. L'applicazione di questo **ricrea il pod CH** (singola replica → \~30–60s di downtime analitico); fallo in una finestra di traffico basso.
2. Mantieni le cache in `deploy/base/clickhouse/configmap.yaml` proporzionate al limite — cache piccole (pochi centinaio MiB) sono sicure su un pod piccolo; aumentale solo insieme a un corrispondente aumento del limite di memoria. `max_memory_usage` per query è impostato esplicitamente nel profilo `users.xml` (vedi la sezione di nodo fisso di seguito) e viene mantenuto sotto il cap a livello di server (`0.9 × limit`) quindi nessuna singola query è *consentita* più RAM del contenitore.
3. Se il nodo stesso è il ceiling, controlla la memoria dell'host che ClickHouse può vedere:
   ```bash theme={null}
   kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \
     "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'"
   ```
   Se è solo un po' più in alto del limite del pod, sposta ClickHouse su un nodo più grande (ottimizzato per memoria) — tramite un selettore di nodo/affinità nel tuo overlay — prima di aumentare ulteriormente il limite.

**Quando non puoi aggiungere memoria: esegui le query in RAM e fallisci velocemente — non versare su un disco lento.** Se il nodo è fisso e il pod non può crescere, cappare quello che qualsiasi singola query può usare (quindi una query non può prendere l'intero nodo) e, su un **disco dati lento (non-SSD)**, **non** lasciare che le aggregazioni/ordinamenti grandi si versino su disco. Versare su un disco lento è più lento del timeout di lettura del client del server, quindi una query che versa restituisce un dashboard `500` a metà volo mentre ClickHouse continua a macinare — mantenere le query in RAM e rifiutare la rara sovraspesa velocemente (`MEMORY_LIMIT_EXCEEDED`, sub-secondo) è ciò che ripristina il caricamento. Nota una gotcha di ClickHouse per l'applicazione di questi:

* **Questi sono impostazioni di *profilo*, e ClickHouse legge `<profiles>` solo da `users_config` (`users.xml` / `users.d/*.xml`) — mai da `config.d`.** Un blocco `<profiles>` posto in `config.d/agenteye.xml` è **silenziosamente ignorato** (`max_execution_time`, `max_memory_usage`, ecc. semplicemente non si applicano). La configurazione in bundle quindi li spedisce come una chiave `users.xml` su ConfigMap `clickhouse-config`, montata in `/etc/clickhouse-server/users.d/agenteye.xml`.
* I default spediti: `max_memory_usage` (per-query ceiling — una query non può consumare l'intero budget del server), `max_bytes_before_external_group_by` / `max_bytes_before_external_sort` = **`0` (versamento disabilitato)** quindi le query rimangono in RAM invece di strisciare sul disco lento, e `max_execution_time` (guardia runaway, allineato al timeout di lettura del client del server).
* **Verifica che siano live** (questo è anche come tu rilevi la gotcha di config.d):
  ```bash theme={null}
  kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \
    "SELECT name, value FROM system.settings
     WHERE name IN ('max_memory_usage','max_bytes_before_external_group_by','max_execution_time')"
  ```
  Aspettati un `max_memory_usage` diverso da zero e `max_bytes_before_external_group_by = 0`. Se `max_memory_usage` legge `0`/default, il profilo non viene applicato — controlla che le impostazioni vivano in un mount `users.d`, non `config.d`.

Trade-off: con versamento disabilitato, una query il cui set di lavoro eccede `max_memory_usage` è **rifiutato** (`MEMORY_LIMIT_EXCEEDED`) piuttosto che completarsi lentamente — su un disco lento quel rifiuto veloce è preferibile, perché una query che versa supererebbe il timeout del client e fallirebbe comunque. Se il tuo disco dati è **veloce (SSD)**, puoi invece aumentare le soglie di `max_bytes_before_external_*` per lasciare che le query grandi si versino su disco e si completino.

***

## Multi-tenancy (organizzazioni)

### Errori durante l'aggiornamento che abilita le organizzazioni (pod del server vecchio/nuovo misti)

**Sintomo:** durante un'implementazione rolling della release che abilita l'org, alcuni richieste falliscono: i log del server mostrano `there is no unique or exclusion constraint matching the ON CONFLICT specification` nel percorso `api_keys`, e/o gli avvisi/Slack/canali webhook smettono di funzionare mentre il rollout è in volo.

**Causa:** l'aggiornamento sostituisce il vecchio indice univoco a livello di istanza su `api_keys(name)` con indici parziali per-org, e sposta le impostazioni del canale di allerta (e `default_user_permissions`) dalla tabella `settings` globale all'org per-org `org_settings`. Un pod del server **vecchio** ancora emette `ON CONFLICT (name)` (ora nessun constraint corrispondente) e legge ancora la configurazione del canale dalle vecchie righe `settings` (ora vuote). I pod vecchi e nuovi non possono coesistere in sicurezza per questi due percorsi.

**Correzione:** non eseguire lentamente roll questo particolare aggiornamento su versioni miste. Passare in modo pulito: scalare il server vecchio a zero (o utilizzare una breve finestra di manutenzione) e portare la nuova versione con le sue migrazioni, piuttosto che eseguire repliche vecchie e nuove fianco a fianco. Il traffico normale e l'ingest riprendono immediatamente dopo il cutover; questo influisce solo sulla finestra di transizione della versione.

### Il provisioning di un'organizzazione fallisce su `CREATE USER` / `CREATE ROW POLICY`, oppure un'org può leggere i dati di un'altra org

**Sintomo:** la creazione di un'org restituisce un errore che menziona `CREATE USER`, `CREATE ROW POLICY`, o "access management is disabled"; o, peggio, i membri di un'org vedono gli eventi/valutazioni di un'altra org nell'editor SQL o nell'assistente.

**Causa:** l'isolamento per-org è applicato da un utente ClickHouse dedicato + politica di riga per org. Questo richiede **access management** di SQL per essere abilitato e `users_without_row_policies_can_read_rows=false` su ClickHouse. Con access management spento, il provisioning non può creare l'utente/politica; con il default della politica di riga lasciato al suo valore permissivo, un utente che ha SELECT ma nessuna politica legge **tutte** le righe (fail-open).

**Correzione:** usa la configurazione `deploy/base/clickhouse/` in bundle, che imposta entrambe. Se esegui la tua configurazione ClickHouse, abilita SQL access management sull'utente server-interno e imposta `users_without_row_policies_can_read_rows=false` (vedi `deploy/base/clickhouse/configmap.yaml`), quindi riavvia ClickHouse e ricrea l'org con la CLI `agenteye-orgctl` (vedi [enterprise-docs/tenant-management.md](/it/agenteye/tenant-management)).

### Gli utenti dell'org perdono l'accesso a ClickHouse dopo il cambiamento di `ORG_CH_SECRET`

**Sintomo:** l'editor SQL e l'assistente AI improvvisamente restituiscono errori di autenticazione ClickHouse per ogni organizzazione, immediatamente dopo che `ORG_CH_SECRET` è stato modificato o impostato in modo incoerente su repliche.

**Causa:** la password ClickHouse di ogni org è derivata come HMAC di `ORG_CH_SECRET`. Ruotarlo (o eseguire repliche con valori diversi) invalida le credenziali ClickHouse memorizzate di ogni org; la password derivata non corrisponde più all'utente provisioning.

**Correzione:** imposta `ORG_CH_SECRET` su un unico valore forte **prima** di provisioning una seconda org e mantienilo stabile e identico su ogni replica del server. Il riconciliarsi del tempo di avvio del server riprovvede l'utente ClickHouse di ogni org dal secret corrente all'avvio, quindi un riavvio del server su tutte le repliche (con il secret coerente) guarisce gli utenti orfani. Tratta il valore come un secret di lunga durata; non ruotarlo casualmente. Come rete di sicurezza, se `ORG_CH_SECRET` è lasciato al default di sviluppo built-in (cioè non impostato), il riconciliarsi del tempo di avvio **salta** le organizzazioni non predefinite e registra un errore anziché riscrivere le loro credenziali ClickHouse al valore dev pubblicamente noto, quindi una singola replica che si riavvia senza il secret non può rompere le altre repliche. Imposta il secret in modo coerente e riavvia per provisioning quelle org.

### L'assistente AI restituisce 400 / rifiuta di chattare dopo l'abilitazione delle organizzazioni

**Sintomo:** la dock dell'assistente si carica ma ogni messaggio torna con un errore (HTTP `400`), e l'agente registra una richiesta `/chat` senza org rifiutata.

**Causa:** l'agente è consapevole dell'org e fallisce chiuso; rifiuta un `/chat` che non porta contesto organizzativo. Questo accade durante un rollout transizionale dove l'agente è stato aggiornato ma il dashboard che invia la richiesta non è ancora org-aware.

**Correzione:** termina il rollout in modo che il dashboard invii il contesto dell'org (lo stato finale normale, nessun flag necessario). Per colmare il divario mentre un dashboard non ancora org-aware parla a un agente org-aware, imposta `AGENTEYE_AGENT_ALLOW_NO_ORG=1` sul servizio `agent` in modo che effettui il fallback all'org `default` anziché rifiutare, e cancellalo una volta che l'aggiornamento del dashboard arriva. Vedi il riferimento env in [enterprise-docs/assistant.md](/it/agenteye/assistant#environment-variable-reference).

***

## Audit

### Un audit non viene mai eseguito (il prossimo run continua a scivolare, nessuna cronologia di esecuzione)

**Sintomo:** la pagina di audit mostra *last run: never*, o `next run` continua a muoversi nel futuro senza una riga che appare nella cronologia di esecuzione.

**Causa:** l'audit è disabilitato (gli audit disabilitati non hanno voce nella coda), oppure i worker di audit del server non riescono a rivendicare il lavoro.

**Correzione:** conferma che l'audit sia **abilitato** (il pulsante esegui-ora lo richiede). Quindi controlla i log del server per `audits pipeline started` all'avvio e per errori `audits:` — una riga `claim_due failed` punta alla connettività di Postgres. `AUDIT_WORKERS` predefinito `1`; deve essere ≥ 1 affinché qualsiasi audit venga eseguito.

### Le esecuzioni di audit hanno successo ma non trovano nulla

**Sintomo:** la cronologia di esecuzione mostra `succeeded` con `findings: 0` anche se `/errors` chiaramente mostra guasti.

**Causa:** la finestra di scansione non copre i guasti, o i filtri di ambito li escludono.

**Correzione:** controlla la finestra della riga di esecuzione (`window_from → window_to`) rispetto a quando i guasti si sono verificati — in modalità `since_last` ogni esecuzione esegue la scansione solo dall'esecuzione precedente riuscita, quindi i guasti più vecchi vengono visualizzati solo dalla *prima* esecuzione o da un audit a `fixed`-window. Amplia `scope` (ambienti / id agenti). Le statistiche di esecuzione mostrano `policy_hits` (quanti criteri deterministici si sono attivati) e `improvements` (quanti l'indagine AI ha registrato) — se entrambi sono 0, la finestra/ambito genuinamente non ha visto nulla.

### L'esecuzione dice `analysis_unavailable` e produce solo risultati di politica

**Sintomo:** le statistiche di esecuzione includono `analysis_unavailable` e i soli risultati sono `kind: policy`; nessun miglioramento AI appare.

**Causa:** l'indagine agenziale non poteva essere eseguita: il server non riesce a raggiungere il servizio agent (`AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` non impostato sul **server** — l'audit riutilizza la connessione dell'assistente), il servizio assistente non ha LLM configurato, oppure la chiamata ha generato errore/timeout (la stringa `analysis_unavailable` ha il dettaglio). Il pass di politica deterministica è il floor — sempre viene eseguito — quindi l'audit comunque ha successo con i suoi risultati di sicurezza.

**Correzione:** imposta `AGENTEYE_AGENT_URL` (ad es. `http://agent:9100`) e `AGENTEYE_AGENT_TOKEN` sul **server** — gli stessi valori che l'assistente dashboard usa già (i manifesti/compose in bundle ora li innestano) — e configura un LLM sul servizio assistente (vedi [assistant.md](/it/agenteye/assistant)), quindi esegui di nuovo. Una grande indagine potrebbe avere bisogno di un `AUDIT_LLM_TIMEOUT_MS` più grande (server) — mantenerlo superiore al `AGENTEYE_AUDIT_TIMEOUT_MS` dell'agente.

### La sandbox del codice di audit è disabilitata (`sandbox_available: false`)

**Sintomo:** `/health` dell'agente mostra `sandbox_available: false`, e le esecuzioni di audit notano che la sandbox non è disponibile; l'AI indaga solo con SQL.

**Causa:** la sandbox bubblewrap in-pod ha bisogno di **user namespace non privilegiati**, che il profilo seccomp del pod o il kernel del nodo stanno bloccando.

**Correzione:** imposta `seccompProfile: Unconfined` (k8s) o `security_opt: [seccomp:unconfined]` (compose) sull'agente, e conferma che il kernel del nodo consenta namespace utente non privilegiati (alcune immagini gestite, ad es. GKE COS, le disabilitano). Dove non puoi abilitarlo, questo è previsto e sicuro — l'auditor degrada a SQL-only automaticamente. Vedi [deployment.md](/it/agenteye/deployment).

### Il rapporto di audit email non viene consegnato

**Sintomo:** un audit ha esposto nuovi risultati ma nessun email è arrivato.

**Causa:** l'audit non ha un canale **email** allegato, l'email è disabilitato org-wide in `alerts.enabled_channels`, non ci sono destinatari, o SMTP non è configurato.

**Correzione:** allega un canale email all'audit, assicurati che `email` sia in `alerts.enabled_channels`, imposta i destinatari (sul canale o tramite `alerts.email_default_recipients`), e configura SMTP (lo stesso trasporto utilizzato dagli alert + email OTP). L'email viene inviata solo quando un'esecuzione produce **almeno un** risultato nuovo.

### Un motivo mutato o dismesso mantiene la sua vecchia pagina di risultati ma mai si riclassa

**Sintomo:** dopo aver messo a tacere un risultato, le esecuzioni successive non fanno mai riapparire quel motivo — anche se ancora si verifica.

**Causa:** questo è il comportamento progettato: mute/dismiss sono soppressioni durevoli keyed sull'impronta del motivo.

**Correzione:** apri il risultato e usa **reopen** per cancellare la soppressione; l'esecuzione successiva classificherà di nuovo il motivo. Usa **resolve** (non mute) per i motivi "fixed" di cui vorresti sentire parlare se regressano.

***

## Ottenere aiuto

Contatta `support@exosphere.host` con:

* La tua versione di AgentEye (dal tag di rilascio)
* Log di contenitore pertinenti (`docker logs <container>`)
* Una descrizione del problema e di ciò che hai già provato
