Runbook — manutenzione settimanale autonoma¶
Chi lo esegue: una Claude Code Routine cloud, ogni venerdì alle 16:00 UTC (18:00 Europe/Rome durante l'ora legale, 17:00 durante l'ora solare). Cosa produce: una patch release
2.1.x, oppure — legittimamente — nessuna release. Autonomia: piena, fino alla pubblicazione della release inclusa.Questo file è la fonte di verità del processo. La routine cloud contiene solo un prompt breve che punta qui: per cambiare il comportamento settimanale si modifica questo documento, non la routine.
0. Contesto minimo¶
Synapse è un wiki AI self-hosted: FastAPI (Python 3.11+) + React 19/Vite + Tauri v2 desktop, con Postgres e Qdrant. Prima di toccare qualsiasi cosa:
- Leggi
CLAUDE.md— contiene gli invarianti I1–I9 non negoziabili, le convenzioni di commit e lo stack. Nessun fix può violarli. - Leggi le prime ~100 righe di
CHANGELOG.md— cosa è cambiato nelle ultime release. git log --oneline -30— contesto recente.
1. Regola d'oro: non inventare lavoro¶
Se dopo un'analisi seria non emerge nulla che valga davvero un fix, non forzare una release. Si scrive il report dicendo che il codice è in salute, elencando cosa è stato controllato e con quale profondità.
Una settimana senza release è un esito positivo. Un fix inventato per "riempire" la settimana introduce rischio in un sistema che funziona: è un danno netto.
2. Cosa cercare, in ordine di priorità¶
- Bug veri — logica errata, race condition, gestione errori mancante, edge case
scoperti, risorse non rilasciate,
excepttroppo larghi che mascherano errori reali. - Stabilità — task asincroni senza strong reference (garbage-collected a metà), loop senza bound (viola I7), timeout mancanti, retry senza backoff, query N+1, sessioni/transazioni DB lasciate aperte.
- Sicurezza — segreti che finiscono nei log, input non validati, path traversal,
auth aggirabile, dipendenze con CVE note (
pip-audit,npm audit). - Copertura test mancante su codice critico toccato di recente.
- Drift documentale — documentazione che contraddice il codice: versioni stale,
endpoint rinominati, ADR con
Statussbagliato rispetto a ciò che è implementato. - Dipendenze — aggiornamenti patch/minor sicuri. Mai major.
Dove guardare per primo. Il debito fresco si annida nel codice cambiato di recente:
git log --since="3 weeks ago" --name-only --pretty=format: | sort -u | grep -v '^$'
Poi si allarga ai moduli critici (i "centri di gravità" del progetto):
backend/app/ingest/, backend/app/runtime_state.py, backend/app/rag/retrieval.py,
backend/app/mcp/, backend/app/ops/, frontend/src/store/, frontend/src/components/.
3. Vincoli non negoziabili¶
- È una PATCH release. Nessuna feature nuova, nessun breaking change, nessuna migrazione di schema DB salvo necessità stretta — e se una migrazione serve davvero, è il segnale che il fix è troppo grosso per questa routine: va nel backlog 3.0 (§6).
- Mantra di non-regressione. I flussi esistenti restano funzionalmente intatti. Ogni fix va accompagnato da un test di regressione che fallirebbe senza il fix.
- Mai
git push --force, mai riscrivere la history, mai toccare tag già pubblicati. - Mai commit diretti su
main(la branch protection lo blocca comunque): sempre branch + PR. - Ambito ragionevole: puntare a 1–5 fix mirati. Meglio poco e solido.
- Mai retry alla cieca su una CI rossa: si leggono i log, si capisce la causa, si corregge. Un rerun si giustifica solo dopo aver verificato che il fallimento è transitorio (es. timeout di rete in upload).
4. Gate di qualità — tutti verdi prima della PR¶
Backend (da backend/; se manca il venv: python -m venv .venv && .venv/bin/pip install -e ".[dev]"):
ruff check app/ tests/
black --check app/ tests/
mypy app # strict
pytest -q # ~3160 test — deve restare verde, coverage gate 82%
Frontend (da frontend/; npm ci se serve):
npx tsc --noEmit
npx eslint src/
npx prettier --check "src/**/*.{ts,tsx,css}" vite.config.ts
npx vitest run # ~2550 test
Se un gate fallisce per colpa delle modifiche fatte, si sistema. Se fallisce per un problema preesistente e scorrelato, non si forza: si annota nel report e si restringe l'ambito della settimana.
5. Rilascio (solo se è stato fatto almeno un fix)¶
Prossima patch: 2.1.7 → 2.1.8 → 2.1.9 → … Nell'ordine esatto:
- Branch:
git checkout -b fix/weekly-<YYYY-MM-DD> - Commit dei fix. Formato:
fix(<modulo>): <descrizione> [<feature-id>]— ogni commit referenzia almeno un ID feature (K1–K8/F1–F18, vediCLAUDE.md§4). Firma:Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> - Bump versione:
python scripts/bump_version.py bump X.Y.Z→ deve stampareAll files agree(7 superfici allineate). - Rigenera gli artefatti — se salti questo passo il Docs Gate in CI fallisce.
È già successo: una release è stata bloccata per un
schema.mmdnon rigenerato.
cd backend && python scripts/generate_openapi.py && python scripts/generate_er.py && cd ..
python3 scripts/check_adr_index.py # deve dire "0 error(s)"
L'ER va rigenerato ogni volta che cambiano i modelli SQLAlchemy (invariante I8).
5. CHANGELOG.md — nuova sezione in cima, Keep-a-Changelog + SemVer:
## [X.Y.Z] — YYYY-MM-DD — "nome-breve", con ### Fixed / ### Changed / ### Security.
Si spiega la causa radice, non il sintomo.
6. docs/release-notes/vX.Y.Z.md — versione estesa dello stesso contenuto, più una
sezione ## Upgrade notes.
7. mkdocs.yml — voce in cima a nav: → Release Notes:.
8. Commit release: chore(release): X.Y.Z — <nome-breve>
9. Push + PR: gh pr create con Summary + Test plan (checkbox spuntate su ciò che è
stato realmente eseguito).
10. Attendere la CI: gh pr checks <N> in polling. I job durano fino a ~7 minuti; gli
E2E (Playwright + Docker) sono i più lenti. Non mergiare finché non è tutto verde.
Su fallimento: gh api repos/Emanuele-Chiummo/llm-wiki-synapse/actions/jobs/<job-id>/logs.
11. Merge: gh pr merge <N> --squash --delete-branch
12. Rilascio:
```bash
gh workflow run release-cut.yml -f version=X.Y.Z
gh workflow run release-notes-sync.yml
gh workflow run desktop-release.yml --ref vX.Y.Z
```
Attendere il completamento della desktop-release. Tempi normali: macOS ~8-10 min,
Windows ~10 min, **`marker-image` ~25-35 min** (build multi-arch con PyTorch: è
lenta, *non* bloccata — non interromperla). Verifica finale:
```bash
gh release view vX.Y.Z --json assets -q '.assets[].name'
```
Devono comparire sia gli asset macOS (`.dmg`, `.app.tar.gz` + `.sig`) sia Windows
(`_x64-setup.exe` + `.sig`, `portable-x64.exe`).
Se gh non risulta autenticato nell'ambiente: fermarsi dopo il push del branch e
dirlo esplicitamente nel report.
Trabocchetti già pagati (non ripeterli)¶
| Sintomo | Causa | Prevenzione |
|---|---|---|
| Docs Gate rosso | ER/OpenAPI non rigenerati | Passo 4, sempre |
| Docs Gate rosso | ADR nuovo non linkato in docs/adr/index.md |
check_adr_index.py in locale |
| Windows build rossa | windows-latest usa PowerShell |
shell: bash esplicito sugli step POSIX |
gh run rerun rifiutato |
Il run è ancora in corso | Aspettare che tutti i job finiscano |
| Upload asset fallito | Timeout TLS transitorio | Rerun del solo job fallito, a run concluso |
6. Backlog 3.0¶
Se emerge qualcosa di troppo grosso per una patch — refactor architetturali, feature,
breaking change, migrazioni pesanti — non si fa. Si aggiunge una voce a
docs/reference/ROADMAP-3.0-IDEAS.md con:
- titolo
- problema osservato
- evidenza (
file:riga) - impatto stimato
- sforzo stimato (S / M / L)
Il file aggiornato entra nella PR della settimana insieme ai fix.
7. Report finale¶
Si chiude sempre con un report in italiano, anche a zero release:
- Cosa è stato analizzato — aree, file, profondità.
- Bug trovati e corretti — ognuno con la causa radice in una frase.
- Cosa è stato deliberatamente NON toccato e perché.
- Stato release — link alla release GitHub + conferma asset macOS/Windows, oppure il motivo per cui non c'è stata release.
- Nuove voci aggiunte al backlog 3.0.
- Decisioni che richiedono un umano — tutto ciò che è stato lasciato in sospeso.