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 <noreply@anthropic.com>
This commit is contained in:
AgileHub VIGILE 2026-05-30 09:17:17 +02:00
parent 4924075142
commit f8f78b5ece
2 changed files with 189 additions and 0 deletions

View File

@ -25,6 +25,60 @@
**Spec completa**: `STANDARD_TIMEZONE_CONVENTIONS.md` (slug `timezone-conventions` v1.0, owner VIGILE). **Spec completa**: `STANDARD_TIMEZONE_CONVENTIONS.md` (slug `timezone-conventions` v1.0, owner VIGILE).
<!-- STANDARD:timezone-conventions:v1.0:end --> <!-- STANDARD:timezone-conventions:v1.0:end -->
## 🔴 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 <container-fpm-nis2> 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 <file> && 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 # NIS2 Agile - Documentazione Progetto
## REGOLE DI GOVERNANCE (LEGGERE ATTENTAMENTE, aggiornate 2026-04-22) ## REGOLE DI GOVERNANCE (LEGGERE ATTENTAMENTE, aggiornate 2026-04-22)

View File

@ -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 <container-nis2-fpm> 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 <nis2-fpm> kill -USR2 1
3. smoke: curl https://nis2.agile.software/<endpoint> → 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 <file> && git commit -m "[FEAT] descrizione"`).
- Per work-in-progress di più step → branch dedicato (`git checkout -b feat/<nome>` 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.