chore(claude): architettura base .claude — skill preventivo e audit, hook di guardia, piani nel repo

La cartella aveva dentro solo rules/ e i settings: nessun posto dove mettere una
skill, un hook o un piano. Ora ha lo scheletro completo e un .claude/CLAUDE.md che
spiega cosa va dove — non duplica CLAUDE.md di progetto, che resta quello che comanda.

Due skill locali (le altre restano globali in ~/.claude/skills/):
- /preventivo — la catena agent.ts → schema.ts → assemble.ts → ProposalDeck e i tre
  modi di romperla, di cui uno solo fa rumore. Nessun prompt di generazione qui
  dentro: quello vive in agent.ts ed e' l'unico. Porta check-profilo.sh.
- /audit — guida scripts/audit-fonti.ts, nuovo, che mette in moto le cinque fonti di
  src/lib/audit/sources/, in prod dal 2026-08-19 ma mai chiamate da nessuno. Provate
  su giojello.com: 5 su 5, 42,7 s, PageSpeed mobile 58 / desktop 93.

Due hook, provati a mano (6 casi il primo, 5 il secondo):
- guardia-migration.sh BLOCCA l'SQL distruttivo sulle entita' protette — il vincolo
  Data Safety (LOCKED) fatto rispettare dalla macchina invece che dalla memoria.
- guardia-token.sh AVVISA sulle classi Tailwind grezze. Non blocca: con ~450
  occorrenze di debito, bloccare lo renderebbe un ostacolo da disattivare.

I tre piani di v2.5 entrano nel repo: stavano solo in ~/.claude/plans/ e STATE.md
avvertiva che senza quelli la milestone non era ricostruibile. Passati al setaccio
per credenziali prima di committarli.

Corretta in rules/memory-discipline.md la chiave della memoria persistente: e'
…-Vault-IAMCAVALLI-hub, non quella del workspace. Sedici file stavano nella prima,
la regola indicava la seconda.

Impeccable resta abilitato solo a livello globale: fuori da settings.json locale.

Nessun tocco al prodotto. Build e lint verdi, lint identico al baseline.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-26 16:09:14 +02:00
parent bec7e039d7
commit 817a8cd5d1
22 changed files with 1601 additions and 24 deletions
+85 -4
View File
@@ -30,7 +30,7 @@ schema dell'audit, nessuna pagina. La pausa è una scelta del 2026-08-19 — pri
### Modifiche hub (richieste 2026-08-18)
Tre aree: dashboard, progetti, pipeline. Piano in
`~/.claude/plans/sei-arrivato-qua-search-recursive-kettle.md`, **fuori dal repo**.
[`.claude/plans/v2.5-modifiche-hub.md`](.claude/plans/v2.5-modifiche-hub.md).
**In produzione dal 2026-08-19** (commit `4b135ce``19ed377`):
@@ -377,6 +377,85 @@ tab Pagamenti per vederlo. (2) Due `paid_at` storici valgono il **primo del mese
li legge come «Pagato il 1 mar 2026». Se il giorno vero era un altro, si corregge dal nuovo
campo.
### Architettura `.claude/` (2026-08-26)
Configurazione, non prodotto: l'unico file di codice che nasce qui è `scripts/audit-fonti.ts`.
`hub/.claude/` aveva tre cose dentro — `rules/`, `settings.json`, `settings.local.json` — e
nessun posto dove mettere una skill, un hook o un piano. Ora ha lo scheletro completo e un
**`.claude/CLAUDE.md`** che spiega cosa va dove. Non è «il CLAUDE.md che mancava»: quello di
progetto sta alla radice ed è lui a comandare. Questo è la guida della cartella di
configurazione, e si carica quando ci lavori dentro.
**Due skill locali** (le altre restano globali in `~/.claude/skills/`, e copiarle qui
significherebbe averne due destinate a divergere):
- **`/preventivo`** — non contiene un prompt di generazione, e non deve averlo: quello vive
in `agent.ts` ed è l'unico. Contiene la mappa della catena `agent.ts → schema.ts →
assemble.ts → ProposalDeck + sections/`, con la tabella dei tre modi di romperla — e solo
uno fa rumore. Campo nello schema e non nel prompt: **ogni** generazione muore con
«Contenuto AI non valido». Campo nel prompt e non nello schema: Zod lo scarta in silenzio.
Campo nello schema senza sezione che lo legge: generazione verde, sezione assente.
Porta anche `check-profilo.sh`, il preflight sui dati finti.
- **`/audit`** — guida `scripts/audit-fonti.ts`, nuovo, che mette in moto le cinque fonti di
`src/lib/audit/sources/`, in produzione dal 2026-08-19 ma **mai chiamate da nessuno**.
Provate su giojello.com il 2026-08-26: cinque su cinque, **42,7 s** (PageSpeed 34,2), tre
pagine raccolte, CrUX disponibile a livello URL, PageSpeed mobile 58 / desktop 93. Il
grezzo finisce in `audit-fonti-<dominio>.json`, gitignorato: è lì che ogni numero del
documento dovrà essere rintracciabile. Distinto da `spike-audit.ts`, che è un altro
attrezzo e risponde a un'altra domanda.
**Due hook di guardia**, provati a mano prima di fidarsene (6 casi il primo, 5 il secondo):
- `guardia-migration.sh` **blocca** — è il vincolo Data Safety (LOCKED) fatto rispettare dalla
macchina invece che dalla memoria. Toglie i commenti e spezza per `;` prima di guardare, così
«non fare mai DROP TABLE payments» dentro un commento non fa scattare nulla, e
`ALTER TABLE clients DROP COLUMN token` sì. Fuori da `src/db/migrations/` non ha voce.
- `guardia-token.sh` **avvisa e basta**. Bloccare, con ~450 occorrenze di debito già in casa,
lo renderebbe un ostacolo da disattivare invece di un promemoria da leggere. Whitelist per
le eccezioni sanzionate: `StatusBadge`, `AdminShell`, `mailer`, `globals.css`,
`design-reference/`.
**I tre piani della milestone sono entrati nel repo.** Stavano solo in `~/.claude/plans/` con
nomi generati a caso, e STATE.md avvertiva che senza quelli v2.5 non era ricostruibile: un
piano che vive sul portatile di chi l'ha scritto non è documentazione, è un ricordo. Passati
al setaccio per credenziali prima di committarli — dentro ci sono nomi di variabili
d'ambiente, mai i loro valori.
Corretta anche una riga di `rules/memory-discipline.md` che mandava nel posto sbagliato: la
memoria persistente di hub sta sotto la chiave `…-Vault-IAMCAVALLI-hub`, non quella del
workspace senza suffisso. Sedici file erano nella prima, la regola indicava la seconda.
#### Due cose trovate sul preventivo, e non risolte
Nessuna delle due è stata toccata: sono decisioni, non refusi.
**`profile.ts` spedisce dati placeholder in ogni preventivo generato.** Tre testimonianze sono
letteralmente `{ name: "Cliente 1", quote: "→ Aggiungere testimonianza reale." }`; accanto,
email `simone@iamcavalli.com` e sito `iamcavalli.com` quando il dominio è **iamcavalli.net**, e
titolo «Strategist · Brand & Business» quando il posizionamento è **Full Stack Designer**. Il
file è uno **snapshot**: finisce in `proposals.content` al momento della generazione e ci resta
anche correggendo il file dopo. Non è riempibile a occhio — `brand/prove.md` è ancora
`stato: scheletro-intervista`, con i numeri marcati «da verificare». Quindi la mossa non è
inventare: è **non renderizzare il blocco** finché il dato non c'è, allineare i campi già
verificati, e portare la domanda a chi ha le testimonianze vere. `check-profilo.sh` oggi
fallisce con 19 occorrenze, ed è il comportamento giusto.
**`unitPrice` viaggia nel payload RSC di `/preventivo/[slug]`.** `PricingSection` renderizza
solo `publicPrice ?? servicesTotal` e il nome dei servizi — corretto. Ma `assembleProposal`
mette in `content.offer.tiers[].services[].unitPrice` anche il prezzo unitario, e
`ProposalDeck` è `"use client"`: riceve l'intero `proposal` come prop da un server component,
quindi tutto l'oggetto viene serializzato nella pagina, renderizzato o no. È la stessa trappola
del gate OTP: **sparire a schermo non è sparire**. Verificato leggendo il codice, **non ancora
a schermo** — serve `curl` su un preventivo pubblicato e `LC_ALL=C grep -c unitPrice`. Se
conferma, la correzione è una proiezione client-safe come già fa `client-view.ts` per il
portale, non nascondere una sezione.
Terza, minore: `agent.ts` chiama il modello con `max_tokens: 8192` per uno schema che chiede
fino a 5 problemi + 5 soluzioni + matrice. Se la risposta viene troncata l'errore non dice
«troncata», dice «L'AI ha prodotto JSON non valido» — e manda a cercare nel posto sbagliato.
Il controllo di `stop_reason` costa tre righe.
### v2.5 — Audit (Phases 2730), in pausa
Il servizio di analisi sito (tre livelli: **Radiografia / Prima-Dopo / Rotta**) diventa
@@ -397,9 +476,11 @@ Manca: agent + sintetizzatore + pipeline, storage immagini, editor admin, pagina
pubblica. Dettaglio in [`.planning/ROADMAP.md`](.planning/ROADMAP.md) e
[`.planning/REQUIREMENTS.md`](.planning/REQUIREMENTS.md).
⚠️ **I due piani della milestone stanno in `~/.claude/plans/`, fuori dal repo**
(`…woolly-puddle.md` per il documento, `…radiant-valley.md` per il motore). Senza quei
file la milestone non è ricostruibile.
I due piani della milestone sono **nel repo dal 2026-08-26**:
[`.claude/plans/v2.5-audit-documento.md`](.claude/plans/v2.5-audit-documento.md) per il
documento, [`.claude/plans/v2.5-audit-motore.md`](.claude/plans/v2.5-audit-motore.md) per il
motore. Prima stavano solo in `~/.claude/plans/`, e senza quei file la milestone non era
ricostruibile: un piano che vive sul portatile di chi l'ha scritto non è documentazione.
## Fatto