# PROTOCOLLO.md — demone di trigger gemello-nave (`watch.py`) **Versione:** 4 (11/09/2026 — spostato in `gemello-nave/trigger/`, cartella propria per il componente meccanico, separata dal "cervello" `gemello-nave/` — stessa logica già in uso per `logbook/`, coerenza con la struttura di `archivio/` appena introdotta) Eredita la Costituzione principale. Demone Python puro, nessun LLM in questo processo — vedi `watch.py` per i dettagli tecnici (commento in testa al file). ## Come gira — crontab utente, non systemd Schedulato via `crontab -e` (utente `mauro`, nessun `sudo`): `*/2 * * * * ... watch.py --once`. **Non un servizio systemd**: il piano originale (`Type=simple`, loop persistente interno, `Restart=on-failure`, stesso schema delle altre `servizio-*`) richiedeva `sudo systemctl enable`, bloccato dal classificatore Auto Mode di Claude Code (azione di sistema con permessi elevati, nessun prompt interattivo da approvare — un divieto assoluto, non aggirabile). Il crontab utente ottiene lo stesso risultato pratico (poll a intervallo fisso) senza bisogno di permessi elevati — stesso meccanismo già in uso su questa macchina per `check_job_health.py` (ogni 30 min). `watch.py` supporta comunque un flag `--once` (un solo ciclo, usato dal cron) e una modalità loop persistente senza flag (tenuta per test manuali, non più il meccanismo di produzione). ## Cosa fa A ogni invocazione (ogni 2 min): legge `scripts/slave-mailbox/mailbox.log` dall'ultimo offset persistito (`gemello-nave/trigger/trigger.offset`, accanto allo script). Filtra le righe `check_job_health:`, `logbook:`, `gmail-check:` e `gate-watch:` (perimetro deciso in `archivio/Adrian/progetti/project_gemello_nave.md`, esteso a `logbook:` l'11/09 quando quella cartella è stata spostata dentro `gemello-nave/`, esteso di nuovo lo stesso giorno a `gmail-check:` in shadow mode, e una quarta volta lo stesso giorno a `gate-watch:` quando `servizio-gate-watch` è stato spostato dentro `gemello-nave/gate-watch/` — i suoi fallimenti job, prima riportati via SendMessage diretto da una slave dedicata, ora passano da qui come gli altri tre perimetri). Il filtro tiene per **blocchi**, non riga per riga: una riga che matcha un prefisso apre il blocco, le righe successive che non iniziano con un timestamp ISO8601 (le continuazioni multi-riga, es. i mittenti sotto un evento `gmail-check` con più messaggi) restano nel blocco finché non arriva la prossima riga con timestamp — bug trovato e corretto l'11/09 prima di attivare `gmail-check:` (il filtro riga-per-riga precedente avrebbe scartato le righe di continuazione, lasciando solo l'intestazione "N messaggi nuovi:" senza mittenti). Se trova qualcosa, invoca `gemello-nave` a freddo (`claude -p`, cwd `gemello-nave/` — root del repo, non più annidata sotto `scripts/slave-sentinels/` — così il suo `CLAUDE.md` di ruolo si carica automaticamente) passandole il testo grezzo delle righe nuove. Non giudica mai nulla da solo — la classificazione/decisione è interamente di `gemello-nave` (vedi il suo `CLAUDE.md`). Questo demone si limita a osservare e invocare. ## Costo Zero LLM quando non c'è nulla di nuovo nel perimetro (la maggior parte dei cicli). Un'invocazione `claude -p` (costo reale) solo quando arriva almeno un evento `check_job_health` nuovo. ## Log `watch.log` in questa cartella — un evento per invocazione/errore, stesso formato di `servizio-gate-watch/watch.log`. ## Fase attuale — shadow mode (vedi canvas) Adrian continua a triagare gli stessi eventi `check_job_health` come sempre (il proprio `Monitor` su `mailbox.log` non è stato toccato). Questo demone gira in parallelo per verifica, non sostituisce ancora nulla. Solo dopo un periodo di osservazione con esito positivo, Adrian smetterà di occuparsi lui stesso di questo tipo di evento. ## Limite noto Il perimetro è rigido (`check_job_health:`, `logbook:` e `gmail-check:` soltanto) — non allargarlo senza aggiornare prima il `CLAUDE.md` di `gemello-nave` e questo file.