--- name: project_reminders_sync description: Ripristino mirato del flusso Reminders + Calendario — Apple (via account Microsoft agganciato) → consultazione al volo → smistamento in conversazione, senza demone, DB, né file di landing. type: project --- # Promemoria + calendario iPhone → Adrian (01/08/2026) Mauro scrive i promemoria nell'app nativa Apple Reminders. Quell'account Reminders è agganciato a un account Microsoft, quindi i task atterrano automaticamente anche su Microsoft To Do — nessuna azione manuale sua oltre a scrivere il promemoria. Chiesto esplicitamente da Mauro il 01/08/2026: "fa parte del nuovo framework che stiamo impostando... io inserisco velocemente i promemoria, tu li intercetti e li processi". ## Cosa esisteva prima Il vecchio `outlook_sync.py` (dal 16/03/2026) faceva già questo, ma per calendario+task insieme, scrivendo su `vault.db`/`adrian.db` (architettura a DB, poi smantellata). Rimosso il 29/07/2026 perché rotto in silenzio da 17 giorni (credenziali mancanti, nessuno se ne era accorto) — vedi `archivio/_secrets/servizi.md`. Le credenziali OAuth (`OUTLOOK_CLIENT_ID/SECRET/REFRESH_TOKEN`) erano però rimaste in `.env`, ancora valide. ## Decisione di design (01/08/2026) Non un ripristino 1:1 — riadattato all'architettura attuale (file-based, `archivio/`, niente DB): - **Fase 1 (Reminders/To Do)** e **fase 2 (Calendario)** entrambe attive dal 01/08/2026, stesso giorno — Mauro ha chiesto di procedere subito col calendario invece di aspettare. Calendario confermato agganciato allo stesso account Microsoft (verificato: eventi reali di lavoro presenti in `/me/calendarView`). - **Calendario: consultazione (`--calendario [--giorni N]`) + scrittura** — non tocca `archivio/`/`MEMORY.md` automaticamente in lettura; se emerge qualcosa da tracciare, stesso giudizio caso-per-caso dei promemoria. - **Scrittura aggiunta lo stesso giorno** (Mauro: "il pattern è che tu al volo consulti e modifichi quando hai processato... l'app Reminders è un hook veloce per me"): funzioni libreria `create_task`/`update_task`/`delete_task` e `create_event`/`update_event`/`delete_event` in `reminders_sync.py`, usate via snippet Python al momento del bisogno — niente CLI fissa, coerente con l'uso "al volo". Testato round-trip (crea+cancella) per entrambi il 01/08/2026. Scrivere su Reminders/Calendario è visibile a Mauro sul telefono: si scrive solo quando è chiaro cosa vuole, altrimenti si chiede prima. - **Nessun cron/demone** — deciso da Mauro stesso a metà costruzione ("forse non lo devi neanche schedulare"), proprio per evitare che si ripeta il fallimento silenzioso del vecchio script. Si esegue solo su invocazione (skill `processa-promemoria`). - **Nessun file di landing/inbox** — prima versione scriveva i promemoria nuovi in `archivio/_inbox_promemoria.md` (stesso pattern di `inbox-documenti/`), tolta lo stesso giorno su domanda diretta di Mauro ("ma inbox promemoria ti serve?"): duplicava solo quanto già deciso in conversazione, rischiando di disallinearsi da `scripts/.reminders_state.json`. Oggi: fetch stampa a schermo, smistamento avviene lì per lì nella sessione, nessun file intermedio. - **Smistamento è giudizio di Adrian, non regola automatica**: ogni promemoria può diventare un thread in `memory/MEMORY.md`, una nota in `archivio/`, o essere scartato se già gestito — mai indovinato se ambiguo, si chiede a Mauro. - **Chiusura del cerchio**: quando un promemoria è preso in carico, Adrian lo marca completato su Reminders/Outlook (`reminders_sync.py --complete `) — sparisce anche dal telefono di Mauro, segnale visivo di "gestito". Quelli lasciati aperti per chiarimento non vengono completati. ## Componenti - `scripts/reminders_sync.py` — fetch task pendenti via Microsoft Graph (`/me/todo/lists`), stampa i nuovi a schermo, stato locale in `scripts/.reminders_state.json` (gitignored). - `scripts/reminders_venv/` — venv dedicato (httpx, python-dotenv, pytz), gitignored. - `.claude/skills/processa-promemoria/SKILL.md` — protocollo eseguibile passo-passo. ## Modello di lavoro confermato (01/08/2026, dopo il primo giro reale su 8 promemoria) Non un uso occasionale — è il modello standard: check-in periodico (Mauro segnala o Adrian chiede quando è passato del tempo), Adrian legge i pendenti, smista uno alla volta in conversazione. Mauro ha creato una lista dedicata **"Memory"** in Reminders (oltre a quella di default "Attività"). **Correzione in corsa (stesso giorno)**: la prima idea era completare i promemoria su Reminders una volta presi in carico (sparivano e basta). Mauro ha chiarito che "Memory" è pensata come **destinazione**, non segnale di priorità: quando Adrian processa un promemoria, lo sposta lì **arricchendolo con una nota** (dove è stato archiviato: thread MEMORY.md, file archivio/) invece di farlo solo sparire — diventa un archivio leggibile sul telefono, utile a Mauro e backup per Adrian. Implementato `archive_to_memory()` (Graph non ha "move" diretto: ricrea in Memory con nota, cancella dall'originale). Migrati retroattivamente gli 8 promemoria del primo giro. **Gotcha operativo scoperto durante la migrazione**: l'API Graph ha avuto latenza intermittente (chiamate singole a tratti 30-60s, poi tornate <1s senza causa apparente) — uno script è andato in timeout a metà provocando un duplicato ("Disattivare Perplexity" creato due volte in Memory, ripulito manualmente). Lezione: dopo un timeout a metà operazione, **verificare lo stato reale prima di rilanciare**, non assumere che nulla sia stato scritto. **Seconda correzione, stesso giorno**: Mauro ha chiarito che "Memory" deve contenere solo le cose ancora aperte, non diventare un log permanente — l'archivio vero è già `archivio/`/`MEMORY.md`. I dati puramente storici senza azione residua (i due valori ETF, 156,8k e 147,5k) sono stati eliminati del tutto da Memory subito dopo averli archiviati in `finanze.md`, invece di restarci come traccia. Regola aggiornata: `archive_to_memory` (sposta+arricchisce) solo per chi ha ancora un'azione pendente; `delete_task` diretto per i puri fatti già archiviati altrove. **Terza correzione, stesso giorno — parità 1:1 con `memory/MEMORY.md`**: le note in Memory non devono avere il prefisso "Thread in memory/MEMORY.md:" (ridondante, implicito dal trovarsi lì). Più rilevante: Mauro ha chiesto che "Memory" e la sezione "Thread aperti" di `memory/MEMORY.md` restino sincronizzati nei due sensi — non solo Reminders→MEMORY.md ma anche il contrario. Creati in Memory (con `due_date` dove applicabile) i 4 thread che mancavano: riscaldamento (10/10), investire 28k (03/08), lavoro sui subagenti (03/08), terzo subagente MyICR futuro (senza scadenza). **Gotcha timezone scoperto in questo passaggio**: `dueDateTime`/`lastModifiedDateTime` di Graph sono in UTC — troncare la stringa grezza a `[:10]` vicino a mezzanotte mostra il giorno sbagliato (03/08 letto come 02/08). Aggiunta `_local_date()` in `reminders_sync.py` (converte in Europe/Rome prima di troncare), usata da `fetch_pending_tasks`. ## Estensione appuntamenti (01/08/2026): stesso gate, ma per il calendario Mauro non scrive mai appuntamenti direttamente sul Calendario nativo — se lo facesse bypasserebbe il gate (Adrian non lo vedrebbe mai). Li scrive come todo su Reminders, Adrian li riconosce in triage e scrive lui l'evento vero. **Gerarchia a 3 livelli, non equivalenti** (chiarita da Mauro dopo una prima proposta di Adrian più minimalista, scartata): `memory/MEMORY.md` è il posto primario — quello che Adrian tiene davvero sotto controllo. Reminders "Memory-calendario" (nuova lista, creata via `get_or_create_list`) e Outlook Calendar sono backup/connettori verso l'esterno, non fonti primarie. Quando un appuntamento è passato, Adrian lo toglie da MEMORY.md e da Memory-calendario — resta solo su Outlook Calendar come storico. Lista "Memory-calendario" creata il 01/08/2026 via API (non a mano da Mauro come "Memory") — `get_or_create_list()` aggiunta a `reminders_sync.py` per questo. ## Non ancora deciso - Se i promemoria "scartati perché già gestiti a voce" vadano comunque completati su Reminders o lasciati che Mauro li chiuda lui stesso — oggi: completati solo quelli di cui Adrian scrive effettivamente qualcosa (thread/nota). - I 7 promemoria ambigui nella prima inbox (MonitorOsservatorio x2, "rivedere i TODO", importi con date, "5100 a Alfonso") — rimandati da Mauro, da riprendere. ## Semplificazione (09/08/2026) — da 4 destinazioni a 2 Mauro, durante la vacanza a Campomarino: *"Calendario e promemoria. Mi sembra troppo complicato come stiamo gestendo"*, poi più precisamente *"troppi passaggi con rischio di saltarne qualcuno ogni volta"*. Diagnosi corretta: il modello a 3 livelli descritto sopra (`memory/MEMORY.md` primario, lista Reminders "Memory" backup task, lista "Memory-calendario" backup appuntamenti, più Outlook Calendar) richiedeva una sincronizzazione manuale item per item ad ogni giro di triage — ogni sincronizzazione in più è un punto dove un passaggio può saltare senza che nessuno se ne accorga (stesso pattern del sync Drive fermo 4 giorni, vedi `project_secondbrain_gdrive.md`). **Decisione**: tolte le liste "Memory" e "Memory-calendario". Restano solo due destinazioni vive, entrambe lette direttamente (non più copiate a mano): - **Reminders "Attività"** — input di Mauro, e ora anche dove restano i task presi in carico (completati o cancellati quando gestiti, non più spostati altrove). - **Outlook Calendar** — unico posto per gli appuntamenti, nessun mirror Reminders. `memory/MEMORY.md` smette di duplicare task/appuntamenti con una casa naturale in queste due liste — resta solo per stato senza casa altrove. Le due liste diventano **fonte viva**, lette ad ogni avvio sessione (passo dedicato in `avvio-sessione`, non più delegato al ricordarsi di invocare `processa-promemoria`). **Migrazione eseguita lo stesso giorno** (prima spostato, poi cancellato — per non perdere nulla, come richiesto esplicitamente da Mauro): 7 task da "Memory" ricreati su "Attività" (scadenze passate del 03/08 ripulite, non riproposte come scadenza stale); verificato che tutti gli appuntamenti di "Memory-calendario" avessero già un corrispettivo su Outlook Calendar (vero per tutti tranne uno già scaduto, eliminato senza sostituzione). **Trovato un duplicato reale su Outlook stesso** ("Intervento Riscaldamento" 10/10, doppio identico) e rimosso. Liste "Memory"/"Memory-calendario" cancellate del tutto (non solo svuotate). Skill `processa-promemoria` riscritta per il nuovo modello; `archive_to_memory()` in `reminders_sync.py` rimossa (codice morto, nessuna lista "Memory" verso cui archiviare più). **Bug corretto lo stesso giorno — `mark_processed` esplicito**: Mauro ha chiesto "come fai ad accorgerti se c'è un promemoria nuovo che prima non avevi processato?" — la risposta ha scoperto che lo stato (`scripts/.reminders_state.json`) veniva salvato subito dopo aver *stampato* i promemoria nuovi, dentro `main()`, prima ancora che il triage vero avvenisse in conversazione. Se una sessione si interrompeva a metà, il promemoria spariva dai "nuovi" per sempre senza che nulla fosse deciso. Corretto: `main()` non scrive più stato, solo `mark_processed(task_id, title, list_id)` — chiamata esplicitamente dopo aver davvero smistato un item che resta visibile. Se non viene chiamata, il task ricompare come "nuovo" al prossimo fetch — ridondante ma sicuro. **Tolto anche il gate sugli appuntamenti, stesso giorno**: Mauro ha messo in discussione il valore aggiunto del passaggio "todo su Attività → Adrian riconosce → Adrian scrive l'evento" — *"ma il valore aggiunto che tu processi attivamente il calendario quale è?"*. Risposta onesta: il valore (cross-referenziare, trovare doppioni, dare contesto) viene dalla **lettura**, non dalla scrittura — e Adrian legge già Outlook Calendar ad ogni sessione. Il gate di scrittura non aggiungeva nulla. **Ora Mauro scrive gli appuntamenti direttamente su Outlook Calendar**, come scrive i task direttamente su Attività — stesso principio per entrambe le liste, niente più instradamento todo-vs-calendario da decidere in triage. `create_event`/`update_event`/ `delete_event` restano disponibili solo per quando Mauro chiede esplicitamente ad Adrian di fissare/spostare un appuntamento in conversazione. **Bilancio della giornata**: da 4 destinazioni sincronizzate a mano (con gate di scrittura sia per i task sia per gli appuntamenti) a 2 destinazioni lette in automatico, scritte da Mauro direttamente, con Adrian nel ruolo di lettore/collegatore di contesto — non più gatekeeper.