From f8f78b5ece70b3aba50c52bf1830a2353105ecf0 Mon Sep 17 00:00:00 2001 From: AgileHub VIGILE Date: Sat, 30 May 2026 09:17:17 +0200 Subject: [PATCH] docs(handover): release workflow + hot-reload PHP + disciplina commit (attivita primaria) Aggiunto da AgileHub-side (VIGILE) su autorizzazione esplicita utente, dopo che la sessione NIS2 ha scoperto sul campo 2 lezioni critiche: 1. opcache.validate_timestamps=Off -> ogni edit .php richiede kill -USR2 1 nel container FPM (bind-mount non basta a servire il nuovo bytecode) 2. modifiche non committate vengono revertate dal cron ticket-agent (caso reale: commit d5d83bb ha revertato index.php di una Feature 1 WIP) - Nuovo doc docs/INCOMING_FROM_AGILEHUB_2026_05_30_release_workflow_hot_reload.md - Sezione ATTIVITA PRIMARIA inserita in CLAUDE.md subito dopo lo standard timezone Co-Authored-By: Claude Opus 4.7 --- CLAUDE.md | 54 +++++++ ..._2026_05_30_release_workflow_hot_reload.md | 135 ++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 docs/INCOMING_FROM_AGILEHUB_2026_05_30_release_workflow_hot_reload.md diff --git a/CLAUDE.md b/CLAUDE.md index 4862261..b178edf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -25,6 +25,60 @@ **Spec completa**: `STANDARD_TIMEZONE_CONVENTIONS.md` (slug `timezone-conventions` v1.0, owner VIGILE). +## 🔴 ATTIVITÀ PRIMARIA — Workflow di rilascio + hot-reload PHP + disciplina commit + +> **VINCOLANTE per OGNI modifica di codice su NIS2.** Aggiunto 2026-05-30 da AgileHub-side (VIGILE) dopo che la sessione NIS2 ha scoperto sul campo che il bind-mount NON serve codice "live" e che le modifiche scoperte vengono revertate. + +**Le 3 regole d'oro** (doc completo in `docs/INCOMING_FROM_AGILEHUB_2026_05_30_release_workflow_hot_reload.md`): + +### 1. Hot-reload PHP — dopo OGNI edit `.php` + +```bash +docker exec kill -USR2 1 +``` + +Il bind-mount NON basta: `opcache.validate_timestamps=Off` → senza USR2 gli utenti vedono ancora il vecchio bytecode. USR2 = graceful FPM reload (zero downtime, ~10ms, request in volo finiscono). + +⚠️ **La sezione "ARCHITETTURA: PHP-FPM con BIND MOUNT (LIVE)" più sotto è fuorviante**: il filesystem è live via bind-mount, ma il **bytecode servito** no, finché non fai `kill -USR2 1`. Aggiornare quella sezione a riflettere la realtà. + +### 2. Commit immediato — niente modifiche scoperte + +Appena una modifica funziona (smoke verde post-USR2): +```bash +git add && git commit -m "[FEAT|FIX|DOCS] descrizione" +``` + +**Mai** lasciare modifiche scoperte nel working tree: il cron `ticket-agent-cron.sh` (ogni 2 min) può lanciare `claude -p` che rebase/reverta. **Caso reale 29/5**: commit `d5d83bb` (agent automatico) ha revertato `index.php` di una Feature 1 non committata → persa. + +Per WIP attivo prolungato → semaforo manuale (il cron salta i container con quel lock): +```bash +echo "USER=cristiano STARTED=$(date -Iseconds)" > /tmp/agent-working.lock +# ... lavori ... +rm /tmp/agent-working.lock +``` + +### 3. Push via host se cache token vuota (post-reboot container) + +Il container NIS2 è ancora legacy (non migrato all'helper credenziali vault come `trpg-agile`). Dopo un reboot del container la `git credential-cache` in-memory è vuota → push bloccato. Invece di `git-login` interattivo, **chiedi a VIGILE/AgileHub-side**: +> "VIGILE, NIS2 ha N commit su main da pushare, fallo tu dall'host" + +L'host è migrato all'helper vault, prende il PAT Gitea automatico, pusha sul bind-mount condiviso, ripristina ownership `.git`. Fix definitivo = migrazione vault helper anche per nis2-agile (richiede recreate container). + +### Workflow operativo per ogni modifica + +``` +edit → kill -USR2 1 → smoke (curl) → bump app/version.json → git commit → git push (via host se serve) +``` + +### Cosa NON serve (semplificazione rispetto a TRPG) + +NIS2 è **L1 master-shared** (1 istanza, `nis2.agile.software`). NON servono: plan TSSP in `hub_upgrade_plans`, image Docker build, agent run, retag registry. Quelli sono pattern TRPG **L2 partial-SaaS** per propagare a N tenant — NIS2 ha 1 sola istanza, l'edit + USR2 **È** la propagazione. Tabella di confronto nel doc completo. + +📄 **Doc completo**: `docs/INCOMING_FROM_AGILEHUB_2026_05_30_release_workflow_hot_reload.md` + +--- + + # NIS2 Agile - Documentazione Progetto ## REGOLE DI GOVERNANCE (LEGGERE ATTENTAMENTE, aggiornate 2026-04-22) diff --git a/docs/INCOMING_FROM_AGILEHUB_2026_05_30_release_workflow_hot_reload.md b/docs/INCOMING_FROM_AGILEHUB_2026_05_30_release_workflow_hot_reload.md new file mode 100644 index 0000000..62179c0 --- /dev/null +++ b/docs/INCOMING_FROM_AGILEHUB_2026_05_30_release_workflow_hot_reload.md @@ -0,0 +1,135 @@ +# OUTGOING → NIS2 — Workflow di rilascio + hot-reload PHP (2026-05-30) + +> **Da**: AgileHub-side (VIGILE) +> **A**: sessione Claude `nis2-agile-devenv` (e qualsiasi sessione futura che lavora su NIS2) +> **Trigger**: l'utente ha segnalato che NIS2 non aveva sistematizzato due lezioni critiche scoperte sul campo (hot-reload PHP + disciplina commit). Codifico qui il pattern così non si reimpara da zero. + +--- + +## TL;DR — Le 2 regole d'oro + +1. **Ogni modifica PHP richiede `kill -USR2 1` nel container.** Il bind-mount NON basta: `opcache.validate_timestamps=Off` in produzione → senza USR2 il vecchio bytecode resta in cache, gli utenti vedono ancora la versione precedente. +2. **Committa SUBITO ogni modifica funzionante.** Le modifiche non committate sono a rischio: il cron `ticket-agent` o altri agenti possono rebasare/revertare il working tree (è successo: commit `d5d83bb` ha revertato `index.php` di una Feature non ancora committata). + +--- + +## 1. Hot-reload PHP — il pattern operativo + +NIS2 (e tutti i prodotti PHP della suite con PHP-FPM + opcache) gira con `opcache.validate_timestamps=Off` per performance. Conseguenza: **opcache non rilegge i file da disco**, anche se il bind-mount li ha già aggiornati. Dopo ogni edit di `.php`: + +```bash +docker exec kill -USR2 1 +``` + +Cosa fa USR2 su FPM: **graceful reload** dei workers (zero downtime, request in volo finiscono, i nuovi workers leggono il bytecode fresco). NON serve riavviare il container, NON serve `docker compose restart`. + +**Pattern per ogni modifica PHP:** + +``` +1. edit file.php (sul bind-mount /var/www/nis2-agile/...) +2. docker exec kill -USR2 1 +3. smoke: curl https://nis2.agile.software/ → conferma la nuova versione risponde +4. commit + push (vedi §2) +``` + +Se non sei sicuro del nome esatto del container FPM: +```bash +docker ps --format '{{.Names}}' | grep -iE 'nis2.*(fpm|app|web|php)' +``` + +**Eccezioni** (file che NON richiedono USR2): +- File statici (CSS, JS, immagini, HTML puro) → serviti da nginx/apache, niente cache PHP. +- File JSON/template letti a runtime senza require/include (es. config JSON parsato con `json_decode`). +- `version.json` (il polling client lo rilegge ad ogni richiesta). + +In dubbio → fai USR2, costa ~10ms. + +--- + +## 2. Disciplina commit — non lasciare modifiche scoperte + +**Regola**: appena una modifica funziona (smoke verde dopo USR2), **commit immediato** anche se è una WIP. Niente sit-on di feature funzionanti nel working tree. + +**Perché**: il cron `ticket-agent-cron.sh` ogni 2 minuti può: +- Prendere un ticket OPEN, lanciare `claude -p` nel container → l'agent modifica file, committa, potenzialmente rebase/revert se trova conflitti. +- Altri processi (sync, sso-password-sync, ecc.) possono toccare il working tree. + +Lo conferma il caso reale di ieri: commit `d5d83bb` (agent automatico) ha revertato `index.php` di una Feature 1 NON ancora committata. Persa la modifica → rifatta da zero. + +**Mitigazione**: +- Commit dopo OGNI step funzionante (`git add && git commit -m "[FEAT] descrizione"`). +- Per work-in-progress di più step → branch dedicato (`git checkout -b feat/` poi merge in main quando completo). +- **Heads-up al cron**: se stai lavorando attivamente, crea il semaforo manuale per evitare che il cron parta: + ```bash + echo "USER=cristiano STARTED=$(date -Iseconds)" > /tmp/agent-working.lock + # ... lavori ... + rm /tmp/agent-working.lock + ``` + Il cron salta i container con `/tmp/agent-working.lock` attivo. + +--- + +## 3. Git push se la credential-cache è vuota (post-reboot o container fresco) + +Il container NIS2 oggi è **legacy** (non ancora migrato al vault credential helper come `trpg-agile`). Quindi: +- `git push` chiede il PAT Gitea via `git credential-cache` (in-memory). +- Dopo un reboot/restart del container → cache vuota → push bloccato. + +**Workaround immediato senza git-login interattivo**: chiedi a VIGILE/AgileHub-side di pushare dall'host (l'host ha già l'helper vault). Pattern usato il 29/5: +``` +"Vigile, NIS2 ha N commit su main da pushare, fallo tu dall'host" +→ ssh host: cd /var/www/nis2-agile && git -c safe.directory=. push origin main +→ chown -R git:git .git (ripristina ownership) +``` +Funziona perché `/var/www/nis2-agile` (host) = `/projects/nis2-agile` (container) = stesso bind-mount → i commit fatti nel container sono visibili all'host. + +**Fix definitivo** (richiede ricreate container NIS2): migrazione vault helper, pattern `trpg-agile`. Da fare quando arriva una finestra di manutenzione. + +--- + +## 4. Workflow di rilascio NIS2 — versione semplificata + +NIS2 è **L1 master-shared** (single-instance, `nis2.agile.software`), NON L2 partial-SaaS come TRPG. Quindi **il workflow è molto più semplice di TRPG**: + +| | TRPG (L2 partial-SaaS) | NIS2 (L1 master-shared) | +|---|---|---| +| Frontend | bind-mount master → propaga istantaneo a N tenant | bind-mount → 1 sola istanza, istantaneo | +| Backend | container `trpg-data` per ogni tenant + plan TSSP + agent | nessun container per-tenant, è il container master | +| Plan in `hub_upgrade_plans` | sì (TSSP pipeline) | **no** — NIS2 non è sulla TSSP | +| Build immagine + push registry | sì (per Cat 2) | **no** | +| Bump `version.json` | sì | **sì** (per il polling client di auto-refresh) | +| Commit + push Gitea | sì | **sì** | +| Tag git `vX.Y.Z` | sì | **sì** (igienico, anche se non strettamente necessario) | + +**Workflow operativo NIS2 per una release**: +``` +1. Edit codice (PHP + asset) +2. kill -USR2 1 sul container FPM (per i file .php) +3. Smoke test: curl/browse → verifica funziona +4. Bump app/version.json (versione + build_id + changelog) +5. git add . && git commit -m "[FEAT|FIX|DOCS] descrizione" +6. git tag vX.Y.Z (opzionale ma consigliato) +7. git push origin main --tags (via host se cache token vuota) +``` + +**NON serve**: rebuild immagine Docker, plan in `hub_upgrade_plans`, agent run, retag registry. Quelli sono pattern TRPG per gestire la propagazione a N tenant. NIS2 = 1 istanza, l'edit live è già la propagazione. + +--- + +## 5. Riferimenti + +- **Standard ticket cross-suite**: `nexus-ticket-ms` (porta 4213), routing rules, AI auto-resolve + AWAITING_USER_CONFIRMATION (vedi `docs/ARCHITETTURA_SISTEMA_TICKET.md`). +- **Pattern TRPG L2 partial-SaaS** (per capire la differenza): `memory/reference_trpg_l2_partial_saas_frontend_bindmount.md`. +- **Standard email cross-suite** (se NIS2 manda mail): `email-automation-ms` only, vedi `docs/STANDARD_EMAIL_RELAY.md`. +- **Vault per credenziali NIS2**: `tier1__nis2-app__anthropic`, `tier1__nis2-app__voyage` (già presenti). +- **Helper credenziali Gitea**: oggi NIS2 NON è migrato. Fix futuro = pattern `trpg-agile` in CLAUDE.md AgileServices §"GIT PUSH: Vault-Backed Credential Helper". + +--- + +## 6. Cosa aggiungere al CLAUDE.md di NIS2 + +Quando hai una finestra, aggiungi al **vostro** CLAUDE.md (in `/var/www/nis2-agile/CLAUDE.md` o equivalente) una sezione "**Hot-reload + Release workflow**" con il riassunto delle §1, §2, §4. Così ogni nuova sessione Claude su NIS2 le ha in contesto al boot, senza doverle riscoprire. + +--- + +**Fine documento.** Dubbi/feedback → rispondi con un `INCOMING_FROM_NIS2_...` doc nello stesso pattern, o pingami in chat tramite l'utente.