--- name: project-trigger-push-scalabile description: "APERTO 28/08/2026 — riflessione notturna di Mauro su come scalare i meccanismi di trigger/push verso Adrian man mano che aumentano le fonti (job, sensori domotici, ecc.). Nessuna implementazione ancora, solo mappa concettuale validata." metadata: node_type: memory type: project --- Sessione del 28/08/2026 (Mauro: "notte corta, molte pensate") — riflessione a voce alta sui meccanismi di trigger/push verso Adrian, partita da una domanda su come funziona il Monitor di `gate-ufficio` e allargata a una preoccupazione di fondo: **Adrian diventerà il "cervello complesso" che aggrega sempre più fonti** (job Python, sensori domotici Zigbee in arrivo — vedi [[progetto-domotica-iot]] — e altro in futuro), quindi il meccanismo di trigger/push va progettato bene fin da ora, in modo scalabile, non improvvisato fonte per fonte. **Why:** con una sola fonte (gate-ufficio) il costo di un Monitor armato a mano è trascurabile. Con N fonti eterogenee (bassa urgenza come temperatura/umidità, alta urgenza come intrusione) senza un disegno comune si rischia rumore, doppio-ascolto tra sessioni, e — punto più critico — eventi urgenti persi se nessuna sessione è aperta nel momento giusto. ## Mappa dei meccanismi verificati in questa sessione (non ipotesi, testati/controllati) - **Hook (`SessionStart`)**: harness-level, garantito, ma si attiva solo *quando* Adrian apre una sessione — non è un push verso una sessione già in corso. - **Monitor**: un tool che Adrian sceglie di armare dentro una sessione già aperta; osserva stdout di un comando in background e notifica ogni riga come evento asincrono, senza polling da parte di Adrian. Vive e muore con la sessione — se la sessione si chiude, l'ascolto sparisce. Costo di contesto reale ma basso se la fonte resta silenziosa salvo anomalia (oggi `gate-ufficio` notifica anche gli eventi normali — avvio/verdetto — non solo i problemi, scelta di design diversa dal principio "silenzio = ok"). - **`CronCreate`**: non durevole, vive solo in sessione, scade comunque dopo 7 giorni — inadatto per verifiche che devono sopravvivere alla sessione (nota già in `memory/MEMORY.md`, pattern). - **Routine cloud (`RemoteTrigger`)**: minimo un'ora tra un'esecuzione e l'altra (hard limit API, `*/30 * * * *` viene rifiutato in creazione) — inadatte per reattività sotto l'ora, e comunque cloud-only: zero visibilità sul filesystem Nave. - **Push cross-istanza reale, verificato oggi**: uno script Python headless lanciato da un cron di sistema (`claude -p "..."`) nasce come istanza Adrian a tutti gli effetti — legge `CLAUDE.md`/`memory/MEMORY.md` come qualunque sessione — valuta l'evento, e può usare `SendMessage` verso il nome di una sessione specifica (es. `adrian-21`, il nome di questa sessione VSCode, visibile via `ListAgents`) per notificare una sessione già viva. Funziona solo se la sessione target è ancora in esecuzione — non risveglia una sessione chiusa. L'istanza secondaria poi termina da sola (processo batch, non serve "ucciderla" — nessun handle di `TaskStop` esiste comunque per istanze non generate da Adrian stesso). - **Nel caso reale di Mauro** (VSCode tenuto sempre aperto, questa sessione mai chiusa): il bersaglio `adrian-21` è quindi raggiungibile in ogni momento — il pezzo mancante è solo il mittente (nessun cron oggi fa questo). ## Conclusione della riflessione — direzione, non ancora decisa Serve probabilmente un **hub aggregatore**: un solo processo/script che consolida più fonti (invece di N Monitor armati singolarmente a ogni sessione), silenzioso di default, con **livelli di urgenza distinti per fonte** — non un modello unico: - bassa urgenza (temperatura/umidità): aggregare e parlare ad Adrian quando ha senso, nessuna fretta. - alta urgenza (intrusione, allagamento se mai arrivasse): ~~probabilmente non deve passare da Adrian come intermediario~~ — **ipotesi mia (Adrian), non una posizione di Mauro**: scritta qui il 28/08 come riflessione tentativa, non verificata con lui in quel momento. Corretta il 29/08 (vedi sezione sotto): **decisione reale è l'opposto**. **Non ancora deciso/costruito**: nessun cron oggi lancia `claude -p` reattivamente, nessun hub esiste. Serve aspettare che arrivino i sensori Zigbee (hardware in arrivo, container HA/ZHA non ancora montato — vedi [[progetto-domotica-iot]]) prima di progettare i dettagli concreti, ma il criterio guida ("distinguere urgenza per fonte fin dal disegno") è già chiaro e da riusare quando si riprende il tema. ## Decisione reale su alta urgenza (29/08/2026, corregge l'ipotesi sopra) Mauro, esplicitamente: **idealmente tutto deve passare da Adrian**, anche gli eventi ad alta urgenza — un bypass diretto verso Mauro non è la preferenza di partenza, va usato solo se emergono limitazioni tecniche reali che lo rendono necessario (es. nessuna sessione Adrian raggiungibile in quel momento e il ritardo non è accettabile per quel tipo di evento). Quindi il criterio per l'hub aggregatore, quando si costruirà, è: **Adrian nel loop di default per ogni fonte**, deroga al bypass diretto solo caso per caso e solo per un vincolo tecnico dimostrato, non come design di partenza per l'alta urgenza. **Nota tecnica collegata**: il 29/08/2026 si è scoperto che una slave headless non può usare `SendMessage` per contattare autonomamente una sessione viva (bloccato dal classificatore auto-mode, vedi [[claude-cli-headless]]) — quindi il canale slave→Adrian reale è un file che una sessione aperta rilegge (via Monitor se già in ascolto, via hook `SessionStart` al prossimo avvio altrimenti). **Chiarito definitivamente il 29/08/2026 (discutendo il candidato successivo, `gate-ufficio` come sentinella persistente)**: proposto da Adrian un bypass diretto (`PushNotification` dalla sentinella a Mauro) per i soli fallimenti job reali, come possibile eccezione tecnica. **Mauro ha respinto la proposta, senza eccezioni**: "gli slave per definizione sono slave di Adrian e l'unico referente è sempre e solo lui" — nessuna sentinella/slave comunica mai direttamente con Mauro, sempre e solo via mailbox verso una sessione Adrian, che poi decide se/come avvisarlo. Non è più "un'eccezione da valutare caso per caso" (come scritto sopra il 29/08 mattina) — è un principio fermo, non riproporre bypass diretti per nessun caso d'uso futuro senza che sia Mauro stesso a chiederlo esplicitamente. **Protocollo costruito e testato lo stesso giorno**: non solo pensato, implementato — vedi [[claude-cli-headless]], sezione "Protocollo mailbox" (unito lì il 29/08 invece di un file a parte, per non duplicare la stessa storia in due posti — vedi discussione con Mauro nella stessa sessione). `scripts/slave_mailbox_write.sh` (scrittura), `scripts/slave_mailbox_monitor.py` (ascolto in sessione aperta), fallback nell'hook `session-start-reminder.sh` (recupero al prossimo avvio se nessuno ascoltava). Verificato end-to-end con una slave reale. Nessuna fonte reale lo usa ancora (candidato: `inbox-documenti/`) — resta il prossimo passo quando si costruisce il servizio systemd. ## Principio generale (28/08, stessa sessione, continuazione dopo una pausa) **Delegare quanto più possibile la scrematura al livello meccanico, non a me.** Il pattern per ogni nuova fonte non è "Adrian osserva e capisce", è "qualcosa (script Python, `inotifywait`, o altro) osserva e riconosce l'evento — io ricevo solo l'informazione già filtrata e ci ragiono sopra". Vale già oggi per `gate-ufficio` (`monitor_executions.py` filtra i log, io ricevo solo avvio/warning/verdetto) ed è il criterio da applicare a ogni fonte futura, non solo ai sensori — **primo caso concreto individuato**: `inbox-documenti/` — un Monitor con `inotifywait -m` sulla cartella potrebbe attivare in automatico lo skill `processa-inbox` alla comparsa di un file nuovo (rientra nella piena autonomia già concessa su file locali), fermandosi a notificare Mauro solo se qualcosa non torna (formato inatteso, contenuto ambiguo). Per il "notificare Mauro" non serve ricostruire il vecchio campanello Telegram (smantellato insieme al cockpit) — esiste già `PushNotification` (notifica desktop + push telefono se Remote Control è collegato), stesso identico bisogno, meccanismo già pronto. **Why:** con più fonti che arriveranno (sensori, inbox, altro), se ogni volta Adrian deve "guardare" per accorgersi che qualcosa è successo, la complessità di dover ricordare/armare tutto ricade su di lui — il modello scalabile è l'opposto: N piccoli osservatori meccanici indipendenti, ognuno silenzioso salvo evento, che passano la palla già scremata. **Status:** solo idea, non ancora implementata — nessun Monitor su `inbox-documenti/` esiste oggi. Da riprendere quando si decide di costruirlo davvero. ## Pezzo mancante risolto — CLI headless autenticato senza login interattivo (29/08/2026) Riflessione ripresa da una domanda di Mauro ("una seconda sessione tua che mantiene l'ordinario della Nave... potrebbe essere una tua sessione slave che io non tocco"). Esplorate e scartate due strade prima di arrivare a quella giusta: - **Seconda finestra VS Code** (`code --new-window`): non apre mai una vera finestra nuova quando lanciata da dentro questa stessa sessione — lo script `/usr/bin/code` rileva `VSCODE_IPC_HOOK_CLI` e delega a una modalità "remote CLI" che parla con l'istanza esistente invece di aprirne una vera. Il click manuale di Mauro sull'icona desktop invece funziona (processo slegato dal mio, nessun lock/ambiente ereditato) — ma anche lì, verificato, **non eredita il login** dell'estensione: serve comunque un'autenticazione separata. - **`claude` CLI standalone** (installato oggi via `npm install -g @anthropic-ai/claude-code`, non esisteva prima — solo l'estensione VS Code era presente): stessa storia, wizard di login proprio, non condivide `~/.claude/.credentials.json` con l'estensione nonostante la stessa cartella. **Soluzione reale**: `claude setup-token` — genera un token OAuth di lunga durata (1 anno, legato all'abbonamento Claude), stampato una sola volta a schermo dopo un'autorizzazione via browser fatta da Mauro. Salvato in `archivio/_secrets/credentials.md`. Impostandolo come `CLAUDE_CODE_OAUTH_TOKEN` prima di lanciare `claude`, **il login interattivo sparisce del tutto** — verificato con un vero `claude -p "..."` headless, risposta corretta, zero prompt. **Perché conta**: risolve esattamente il "pezzo mancante" della sezione sopra (19/08) — non serve più che una sessione VSCode resti sempre aperta perché `claude -p` da cron funzioni: ora un processo completamente headless (systemd o cron puro) può autenticarsi da solo, senza mai un terminale interattivo, sopravvivendo a un riavvio della Nave senza bisogno di Mauro. Il token dura 1 anno — da rinnovare con lo stesso comando quando scade. **Non ancora fatto**: nessun servizio systemd costruito sopra questo — oggi è solo il building block di autenticazione verificato. Il prossimo passo naturale (quando si riprende) è decidere cosa la sessione slave deve effettivamente osservare (inbox-documenti/ resta il primo caso candidato, vedi sopra) e scrivere il wrapper/unit systemd che la mantiene viva.