registri dei piani in git (AI-OS#309)
Refs gitea:Adriano/AI-OS#310 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,476 @@
|
||||
# Task 3 — Il radar, e come si mostra ciò che non si sa — report
|
||||
|
||||
**Stato:** completato. 6/6 test nuovi verdi, suite completa allo stato atteso (1 fallito
|
||||
pre-esistente e fuori perimetro, 327 passati), `npx tsc --noEmit` pulito. Commit fatto.
|
||||
|
||||
**Commit:** `7f01ee0` — "longevity: il referto del cliente, e il radar che dice cosa non sa"
|
||||
|
||||
File aggiunti/modificati (solo questi, `git add` esplicito, nessun `-A`/`.`):
|
||||
- `src/lib/longevity/vista.ts` (modificato) — `refertoDi`, `ultimaSessioneDi`, tipi
|
||||
`AsseVista`/`MacroVista`, e le funzioni di supporto private
|
||||
- `src/components/longevity/Radar.tsx` (nuovo) — isola React col radar recharts
|
||||
- `src/components/longevity/MacroScore.astro` (nuovo) — carta di un macro-score
|
||||
- `src/pages/longevity/io.astro` (nuovo) — la pagina del referto, nessuna query diretta
|
||||
- `src/styles/longevity.css` (modificato) — classi `.lg-radar*`, `.lg-macro*`, `.lg-referto`,
|
||||
`.lg-num`
|
||||
- `tests/longevity/referto.test.ts` (nuovo) — i 6 test del brief
|
||||
|
||||
## Procedura seguita (TDD)
|
||||
|
||||
### Step 1-2: test scritto, verificato rosso
|
||||
|
||||
Comando:
|
||||
```
|
||||
npm test -- tests/longevity/referto.test.ts
|
||||
```
|
||||
Esito (prima dell'implementazione): `TypeError: refertoDi is not a function` e
|
||||
`ENOENT` su `src/pages/longevity/io.astro` (non esisteva ancora) — 6 falliti su 6, come
|
||||
atteso.
|
||||
|
||||
### Step 3: implementazione
|
||||
|
||||
**`src/lib/longevity/vista.ts` — `refertoDi(db, sessioneId)`**
|
||||
|
||||
Legge **solo** `leggiScore` (i punteggi congelati in `score`): non chiama mai
|
||||
`calcolaSessione`. Per ogni asse/macro-score:
|
||||
- se `stato === 'ok'`: `{ nome, valore: p.valore, copertura: p.copertura, mancano: [] }`;
|
||||
- altrimenti: `valore: null`, `copertura` letta comunque dalla riga congelata (mai 0 finto
|
||||
quando una copertura parziale esiste davvero), e per gli assi `mancano` calcolato.
|
||||
|
||||
L'ordine dei sette assi (e dei tre macro-score) viene dalla tabella `pesi`
|
||||
(`GROUP BY contenitore ORDER BY MIN(rowid)`, non un `SELECT DISTINCT` senza ordine): rispetta
|
||||
l'ordine di dichiarazione in `registro.ts` (`seedPesi` inserisce nell'ordine degli
|
||||
`Object.entries`), in modo deterministico per il radar.
|
||||
|
||||
**`mancano`: la parte non banale del task.** I sette assi pesano dei *sotto-domini*
|
||||
(`handgrip`, `vo2max`, `questionario_sonno`...), non dei `test_id` — e oggi **nessuna riga
|
||||
di `registro_test` esiste per i sotto-domini fisici** (handgrip, spinta, VO2max, plank...):
|
||||
il registro contiene solo i 20 campi del questionario. Quindi "i test del registro che
|
||||
alimenterebbero quell'asse" non si possono leggere da `registro_test.asse` per un asse
|
||||
fisico — sarebbe sempre vuoto. Ho preso `pesiDi(db, MODEL_VERSION, 'asse', nomeAsse)` (le
|
||||
chiavi = i sotto-domini pesati, dato che esiste già) e confrontato con i sotto-domini che
|
||||
la sessione ha davvero misurato (join `misure`→`registro_test`, `fuori_range=0`,
|
||||
`valore_num IS NOT NULL`). Il sotto-dominio assente si traduce in un'etichetta leggibile
|
||||
via una mappa locale `ETICHETTE_SOTTO_DOMINIO` in `vista.ts` — dato nuovo, necessario perché
|
||||
il registro non ha ancora un'etichetta per quei sotto-domini (arriveranno col piano dei
|
||||
test fisici); non duplica nulla che già esista.
|
||||
|
||||
**`ultimaSessioneDi(db, clientCode)`** — helper nuovo, non nel brief ma necessario: la
|
||||
pagina deve trovare la sessione più recente del cliente loggato senza fare una query da
|
||||
sola. `SELECT id FROM sessioni WHERE client_code=? ORDER BY data DESC, id DESC LIMIT 1`.
|
||||
|
||||
**`src/components/longevity/Radar.tsx`**
|
||||
|
||||
Due serie `recharts` sugli stessi sette assi (recharts vuole un `data` condiviso, non può
|
||||
disegnare un poligono che copre solo alcuni assi):
|
||||
- `noto` (piena): vale `a.valore ?? 0` — dove manca il dato, l'area si ritira verso il
|
||||
centro, non si inventa un valore;
|
||||
- `potenziale` (tratteggiata, `fill="none"`): vale `a.valore ?? 100` — dove il dato c'è
|
||||
coincide col bordo di `noto` (sparisce dietro), dove manca si allarga al massimo,
|
||||
**chiudendo** visivamente il perimetro proprio nei punti mancanti. È l'interpretazione
|
||||
letterale di "una tratteggiata che chiude il perimetro dove il dato manca".
|
||||
|
||||
Sotto il grafico, l'elenco `mancano` per ogni asse ancora incompleto (filtrati su
|
||||
`mancano.length > 0`).
|
||||
|
||||
Colori: hex letterali (`#9c8b70` accento, `#d8d2c8` tratteggio, `#e4dfd7` linea, `#8a8a8a`
|
||||
testo), stesso pattern di `DataChart.tsx` — recharts riceve attributi SVG diretti, non
|
||||
proprietà CSS, quindi `var(--c-accent)` non passa da lì; i valori corrispondono 1:1 ai
|
||||
token di `longevity.css`.
|
||||
|
||||
**`src/components/longevity/MacroScore.astro`**
|
||||
|
||||
Numero se `valore !== null`, altrimenti `'—'` (mai `0`). Bordo tratteggiato
|
||||
(`.lg-card--incompleto`, già esistente dal Task 1) quando insufficiente — stesso
|
||||
linguaggio visivo del radar, non una convenzione nuova. Etichetta derivata dal nome del
|
||||
contenitore (`PERFORMANCE`→`Performance`) con una trasformazione di stringa, non un
|
||||
dizionario da tenere allineato a mano.
|
||||
|
||||
**`src/pages/longevity/io.astro`**
|
||||
|
||||
`Astro.locals.user!.id` → `codicePerUtenteLoggato` → `ultimaSessioneDi` → `refertoDi`.
|
||||
Tre stati gestiti: nessun fascicolo collegato, fascicolo ma nessuna sessione ancora
|
||||
(invito a compilare il questionario), referto pieno. Nessuna query SQL nel file.
|
||||
|
||||
**`src/styles/longevity.css`**
|
||||
|
||||
`.lg-num { font-variant-numeric: tabular-nums; }` applicata ai valori numerici (Fitness
|
||||
Age, macro-score). Nuove classi `.lg-radar*`, `.lg-macro*`, `.lg-referto` — tutte
|
||||
prefissate `lg-`, nessun colore nuovo (solo `var(--c-heading)`, `var(--c-text-light)`,
|
||||
`var(--lg-tratteggio)`, già nella lista ammessa).
|
||||
|
||||
### Step 4: test target verde
|
||||
|
||||
Comando:
|
||||
```
|
||||
npm test -- tests/longevity/referto.test.ts
|
||||
```
|
||||
Output:
|
||||
```
|
||||
Test Files 1 passed (1)
|
||||
Tests 6 passed (6)
|
||||
```
|
||||
|
||||
### Step 5: suite completa + typecheck
|
||||
|
||||
Comando:
|
||||
```
|
||||
npm test
|
||||
```
|
||||
Output (coda):
|
||||
```
|
||||
❯ tests/modifiche-agosto.test.ts (25 tests | 1 failed) 38ms
|
||||
× l'inaugurazione dice la data e che il programma manca ancora 7ms
|
||||
|
||||
FAIL tests/modifiche-agosto.test.ts > promo ed eventi > l'inaugurazione dice la data e che il programma manca ancora
|
||||
AssertionError: expected 'Inaugurazione' to contain '19 settembre 2026'
|
||||
|
||||
Test Files 1 failed | 39 passed (40)
|
||||
Tests 1 failed | 327 passed (328)
|
||||
```
|
||||
Esattamente il rosso pre-esistente dichiarato nel task (fuori perimetro) — nessun altro
|
||||
test rotto, i 6 nuovi inclusi nel verde.
|
||||
|
||||
Comando:
|
||||
```
|
||||
npx tsc --noEmit
|
||||
```
|
||||
Output: nessuno (exit pulito).
|
||||
|
||||
### Step 6: commit
|
||||
|
||||
```
|
||||
git add src/components/longevity/Radar.tsx src/components/longevity/MacroScore.astro \
|
||||
src/pages/longevity/io.astro src/lib/longevity/vista.ts src/styles/longevity.css \
|
||||
tests/longevity/referto.test.ts
|
||||
git commit -m "longevity: il referto del cliente, e il radar che dice cosa non sa"
|
||||
```
|
||||
```
|
||||
[feat/longevity 7f01ee0] longevity: il referto del cliente, e il radar che dice cosa non sa
|
||||
6 files changed, 396 insertions(+), 1 deletion(-)
|
||||
```
|
||||
`git status` dopo il commit: albero pulito (a parte i file fuori dal perimetro di questo
|
||||
task, non toccati).
|
||||
|
||||
## La prova richiesta: rompere il test sul congelamento — esito onesto
|
||||
|
||||
Ho fatto esattamente quanto chiesto: sostituita la lettura (`leggiScore`) con un
|
||||
ricalcolo (`calcolaSessione`) dentro `refertoDi`, per riprodurre "il referto ricalcola
|
||||
invece di leggere i punteggi salvati".
|
||||
|
||||
```diff
|
||||
- import { leggiScore } from './motore';
|
||||
+ import { leggiScore, calcolaSessione } from './motore';
|
||||
...
|
||||
- const punteggi = leggiScore(db, sessioneId);
|
||||
+ const punteggi = calcolaSessione(db, sessioneId) as unknown as ReturnType<typeof leggiScore>;
|
||||
```
|
||||
|
||||
Comando:
|
||||
```
|
||||
npm test -- tests/longevity/referto.test.ts
|
||||
```
|
||||
Esito: **6/6 ancora VERDI, compreso "legge i punteggi congelati, non li ricalcola al
|
||||
volo".** Il test **non** ha intercettato la regressione. Non era un problema
|
||||
d'implementazione della prova: l'ho verificato analiticamente e poi con un secondo
|
||||
esperimento mirato.
|
||||
|
||||
**Perché resta verde — la causa esatta.** Il test del brief muta il peso di
|
||||
`questionario_lifestyle`, che è l'**unico** sotto-dominio pesato dell'asse "Stile di Vita
|
||||
& Sonno" (`{ questionario_lifestyle: 1.00 }`, nessun fratello). Nella media pesata di
|
||||
`aggrega()` (`cascata.ts`), quando un solo elemento è disponibile il suo peso compare
|
||||
identico sia al numeratore (`sommaPesata`) sia al denominatore (`pesoDisponibile`) — si
|
||||
semplifica sempre, qualunque sia il valore. E la `copertura` fa lo stesso:
|
||||
`pesoDisponibile / pesoTotale` con un solo elemento in tutto il dizionario è sempre `1.0`,
|
||||
comunque lo si scali. Cambiare quel peso — con **questi identici dati di seed** (solo le
|
||||
6 risposte di stile di vita) — non può mai produrre un `valore` o una `copertura` diversi,
|
||||
sia che si legga lo score congelato sia che lo si ricalcoli da zero: il test è
|
||||
strutturalmente incapace di distinguere le due cose, non solo in pratica ma per
|
||||
costruzione matematica.
|
||||
|
||||
**Verifica che una mutazione ben scelta invece discrimina davvero.** Ho costruito
|
||||
un esperimento a parte (non nel commit, solo per la prova — poi cancellato): stessa
|
||||
sessione ma con **anche** `q_riposato: 8` fra le risposte (copre `questionario_sonno`
|
||||
con un solo elemento su misura, ma nell'asse "Recupero & Sistema Nervoso" quel
|
||||
sotto-dominio ha *tre fratelli assenti*: `hrv 0.50`, `pressione 0.15`, `hrr 0.15`,
|
||||
`questionario_sonno 0.20`). Con `refertoDi` ancora rotto (ricalcolo), ho azzerato il peso
|
||||
di `hrv` (0.50→0, un fratello **assente**, non l'elemento misurato):
|
||||
|
||||
```
|
||||
npm test -- tests/longevity/_prova-rottura-temp.test.ts
|
||||
```
|
||||
```
|
||||
❯ ... mutare il peso di un sotto-dominio ASSENTE in un asse multi-elemento sposta la copertura ricalcolata
|
||||
AssertionError: expected '{"assi":[...]}' to be '{"assi":[...]}'
|
||||
```
|
||||
Rosso netto: la copertura vera di "Recupero & Sistema Nervoso" passa da `0.20/1.00=0.20`
|
||||
a `0.20/0.50=0.40`, attraversa la soglia (`COPERTURA_MINIMA=0.4`) e l'asse passerebbe da
|
||||
`insufficiente` a `ok` (valore `80` invece di `null`) — con effetto a cascata sui
|
||||
macro-score `ENERGY`/`RECOVERY`. Ripristinato `vista.ts` (tolto il ricalcolo), lo stesso
|
||||
test torna verde:
|
||||
```
|
||||
npm test -- tests/longevity/_prova-rottura-temp.test.ts tests/longevity/referto.test.ts
|
||||
```
|
||||
```
|
||||
Test Files 2 passed (2)
|
||||
Tests 7 passed (7)
|
||||
```
|
||||
Confermato: **rotto → rosso, riparato → verde**, per la mutazione giusta. Il file di prova
|
||||
(`_prova-rottura-temp.test.ts`) è stato cancellato e non è nel commit — non fa parte del
|
||||
perimetro del task, e con la sola compilazione lifestyle (quella del test ufficiale) non
|
||||
esiste alcuna mutazione dei pesi che lo renderebbe rilevante (ogni altro asse ha copertura
|
||||
zero: la stessa scorciatoia `disponibili.length === 0` in `aggrega()` che rende
|
||||
irrilevante qualunque peso quando NESSUN sotto-dominio è misurato).
|
||||
|
||||
**Cosa faccio con questo.** Il test così come specificato nel brief (Step 1, scritto
|
||||
verbatim) **resta nel commit senza modifiche**: è quello richiesto letteralmente
|
||||
dall'assegnazione, e la sua debolezza è specifica alla combinazione "asse a un solo
|
||||
sotto-dominio" + "seed dati che copre solo quello". Non l'ho riscritto di mia iniziativa
|
||||
— ma è un ottavo test (il settimo l'ha trovato il Task 2) che sembra proteggere il
|
||||
congelamento e in realtà, con questi dati, non può proteggerlo per costruzione
|
||||
matematica. Se questa suite deve davvero blindare la regola "non si ricalcola al volo",
|
||||
la mutazione giusta è quella sopra: il peso di un **fratello assente** in un asse con
|
||||
**più di un sotto-dominio dichiarato** e **copertura parziale non-zero** (non un asse a
|
||||
un solo elemento, e non un asse completamente vuoto).
|
||||
|
||||
Le altre tre probe di rottura (mirate ai punti che il brief segnala esplicitamente come
|
||||
critici) **hanno tutte funzionato come dovuto**:
|
||||
- **"un asse senza dati NON porta un numero"**: sostituito `valore: null` con
|
||||
`valore: 0` per l'asse insufficiente → rosso immediato
|
||||
(`expected +0 to be null`). Ripristinato → verde.
|
||||
- **"e dice cosa manca... invece di lasciare un buco"**: `mancanoPer` forzata a
|
||||
restituire sempre `[]` → rosso immediato (`expected 0 to be greater than 0`).
|
||||
Ripristinato → verde.
|
||||
- **"nessuna pagina interroga il database da sola"**: aggiunta una `db.prepare('SELECT 1')`
|
||||
in `io.astro` → rosso immediato (il test intercetta letteralmente `SELECT`/`.prepare(`
|
||||
nel sorgente). Ripristinato → verde.
|
||||
|
||||
Suite completa e typecheck riverificati allo stato finale (dopo tutte le prove e i
|
||||
ripristini):
|
||||
```
|
||||
npm test
|
||||
```
|
||||
```
|
||||
Test Files 1 failed | 39 passed (40)
|
||||
Tests 1 failed | 327 passed (328)
|
||||
```
|
||||
```
|
||||
npx tsc --noEmit
|
||||
```
|
||||
Output: nessuno (pulito).
|
||||
```
|
||||
git status --short
|
||||
```
|
||||
```
|
||||
(nessuna riga: albero pulito, nessun residuo delle prove di rottura)
|
||||
```
|
||||
|
||||
## Cosa esiste alla fine di questo piano
|
||||
|
||||
Come previsto dal brief: un cliente entra, compila il questionario, vede il proprio
|
||||
referto — il radar a sette assi con l'area piena su ciò che sa e il perimetro tratteggiato
|
||||
(più l'elenco di cosa manca) su ciò che non sa ancora, la Fitness Age, le tre carte
|
||||
Performance/Energy/Recovery. Con i dati di oggi (solo questionario, nessun test fisico)
|
||||
**sei assi su sette** risultano tratteggiati — verificato, non solo dichiarato: nel test
|
||||
"restituisce i sette assi" tutti e sette compaiono comunque, e nella sessione di prova
|
||||
solo "Stile di Vita & Sonno" porta un numero.
|
||||
|
||||
Non deployato: come da vincolo del piano (consenso dati sanitari ancora aperto col
|
||||
consulente legale del cliente).
|
||||
|
||||
---
|
||||
|
||||
## Rinforzo dopo revisione (2026-08-22): la prova sul congelamento resa discriminante
|
||||
|
||||
**Stato:** completato. Commit `6630be7` sopra a `7f01ee0`.
|
||||
|
||||
**Il problema confermato dal coordinatore:** la mutazione originale del test "legge i
|
||||
punteggi congelati, non li ricalcola al volo" (peso di `questionario_lifestyle`, unico
|
||||
sotto-dominio del suo asse) passava per un'identita' algebrica — con un solo elemento
|
||||
disponibile in una media pesata, il peso si semplifica sia al numeratore sia al
|
||||
denominatore, quindi non puo' mai produrre una differenza, letto o ricalcolato che sia. Il
|
||||
test era verde per costruzione matematica, non perche' il congelamento funzionasse.
|
||||
|
||||
### Correzione: la mutazione discriminante, con seed dedicato
|
||||
|
||||
`tests/longevity/referto.test.ts`:
|
||||
- Aggiunta `conCoperturaParziale()`, come `conCompilazione()` ma con in piu' la risposta
|
||||
`q_riposato: 8` (copre `questionario_sonno`). Serve solo a questo test: gli altri cinque
|
||||
restano su `conCompilazione()`, invariati.
|
||||
- Il test "legge i punteggi congelati..." ora usa `conCoperturaParziale()` e muta il peso
|
||||
di `hrv` (0.50 → 0) in "Recupero & Sistema Nervoso" — un sotto-dominio **assente** in un
|
||||
asse a **quattro** elementi, dove solo `questionario_sonno` (0.20) e' misurato: copertura
|
||||
vera 0.20/1.00=0.20 (insufficiente, ma `disponibili.length===1`, non 0 — la formula del
|
||||
peso viene eseguita davvero, non bypassata dalla scorciatoia "nessun dato disponibile" di
|
||||
`aggrega()`). Azzerando `hrv` il totale scende a 0.50, copertura vera 0.20/0.50=0.40:
|
||||
attraversa `COPERTURA_MINIMA`, l'asse passerebbe da insufficiente a ok **se** il referto
|
||||
ricalcolasse.
|
||||
- Commento esteso sopra la mutazione: spiega sia perche' QUESTA mutazione discrimina sia
|
||||
perche' quella vecchia (peso dell'unico sotto-dominio di un asse a un solo elemento) non
|
||||
discrimina mai — cosi' chi la tocca fra sei mesi non rimette una versione innocua.
|
||||
|
||||
### La prova di rottura ripetuta sulla versione nuova
|
||||
|
||||
Backup di `vista.ts`, poi iniettato lo stesso ricalcolo di prima (`calcolaSessione` al
|
||||
posto di `leggiScore`):
|
||||
```diff
|
||||
- import { leggiScore } from './motore';
|
||||
+ import { leggiScore, calcolaSessione } from './motore';
|
||||
...
|
||||
- const punteggi = leggiScore(db, sessioneId);
|
||||
+ const punteggi = calcolaSessione(db, sessioneId) as unknown as ReturnType<typeof leggiScore>;
|
||||
```
|
||||
Comando:
|
||||
```
|
||||
npm test -- tests/longevity/referto.test.ts
|
||||
```
|
||||
Output:
|
||||
```
|
||||
❯ tests/longevity/referto.test.ts (6 tests | 1 failed) 20ms
|
||||
× legge i punteggi congelati, non li ricalcola al volo 7ms
|
||||
|
||||
AssertionError: expected '...' to be '...'
|
||||
Expected: ...,"Recupero & Sistema Nervoso","valore":null,"copertura":0.2,...
|
||||
Received: ...,"Recupero & Sistema Nervoso","valore":80,"copertura":0.4,...
|
||||
```
|
||||
**Rosso, come atteso**: l'asse passa da `null`/`0.2` a `80`/`0.4`, con effetto a cascata su
|
||||
`ENERGY`/`RECOVERY`. Ripristinato `vista.ts` dal backup (`diff` col backup: nessuna
|
||||
differenza), rilanciato:
|
||||
```
|
||||
npm test -- tests/longevity/referto.test.ts
|
||||
```
|
||||
```
|
||||
Test Files 1 passed (1)
|
||||
Tests 6 passed (6)
|
||||
```
|
||||
**Verde**, come atteso.
|
||||
|
||||
### Verifiche finali
|
||||
|
||||
```
|
||||
npm test
|
||||
```
|
||||
```
|
||||
Test Files 1 failed | 39 passed (40)
|
||||
Tests 1 failed | 327 passed (328)
|
||||
```
|
||||
Stesso rosso pre-esistente e fuori perimetro (`tests/modifiche-agosto.test.ts > ...
|
||||
inaugurazione ...`); nessuna regressione.
|
||||
|
||||
```
|
||||
npx tsc --noEmit
|
||||
```
|
||||
Output: nessuno (pulito).
|
||||
|
||||
### Commit
|
||||
|
||||
```
|
||||
git add tests/longevity/referto.test.ts
|
||||
git commit -m "longevity: la prova sul congelamento ora discrimina davvero il ricalcolo"
|
||||
```
|
||||
```
|
||||
[feat/longevity 6630be7] longevity: la prova sul congelamento ora discrimina davvero il ricalcolo
|
||||
1 file changed, 44 insertions(+), 3 deletions(-)
|
||||
```
|
||||
`git status` dopo il commit: albero pulito.
|
||||
|
||||
---
|
||||
|
||||
## Rinforzo dopo revisione (2026-08-22): il controllo sui colori ora guarda tutto il foglio
|
||||
|
||||
**Stato:** completato. Commit `a56398e` sopra a `6630be7`.
|
||||
|
||||
**Il problema confermato dal coordinatore:** il test "nelle regole di un punteggio
|
||||
compaiono solo i colori ammessi" (`tests/longevity/pagine.test.ts`) filtrava le regole CSS
|
||||
sul selettore (`if (!/lg-score/i.test(selettore)) continue;`) — un elenco di QUALI regole
|
||||
guardare, non di quali colori sono ammessi. Le classi nuove di questo task
|
||||
(`.lg-radar__voce-nome`, `.lg-radar__intro`, `.lg-macro__nota`) non contengono la stringa
|
||||
`lg-score`, quindi non venivano mai scandite: un colore-giudizio lì dentro sarebbe passato
|
||||
indisturbato nonostante 6 test verdi.
|
||||
|
||||
### Correzione: si scandisce tutto, le eccezioni si dichiarano
|
||||
|
||||
`tests/longevity/pagine.test.ts` — rimossa la riga di filtro sul selettore. Il ciclo ora
|
||||
itera **ogni** regola del foglio (che e' interamente prefissato `lg-` per costruzione,
|
||||
garantito dal test subito sopra). Aggiunto un elenco di eccezioni esplicite:
|
||||
|
||||
```ts
|
||||
const ECCEZIONI: { selettore: string; valore: string; motivo: string }[] = [
|
||||
{
|
||||
selettore: '.lg-form__nav button:last-child:not(:only-child)',
|
||||
valore: '#fff',
|
||||
motivo: "testo bianco per contrasto sul bottone pieno d'accento — non un colore di punteggio",
|
||||
},
|
||||
];
|
||||
```
|
||||
Con lo scan esteso a tutto il foglio, questa era l'unica riga che avrebbe generato un
|
||||
falso positivo (`color: #fff` sul bottone "Avanti/Invia" pieno d'accento — bianco per
|
||||
contrasto testo, non un giudizio sul punteggio): tutte le altre classi nuove del Task 3
|
||||
usano gia' solo `var(--c-heading)`/`var(--c-text-light)`, entrambe nella lista ammessa,
|
||||
quindi passano senza bisogno di eccezioni.
|
||||
|
||||
### Le due prove richieste
|
||||
|
||||
**1. Colore-giudizio su una classe del radar.** Iniettato `color: #cc0000;` in
|
||||
`.lg-radar__voce-nome`:
|
||||
```
|
||||
npm test -- tests/longevity/pagine.test.ts
|
||||
```
|
||||
```
|
||||
❯ ... in tutto il foglio compaiono solo i colori ammessi, salvo le eccezioni dichiarate
|
||||
AssertionError: expected [ Array(1) ] to deeply equal []
|
||||
+ [ ".lg-radar__voce-nome { color: #cc0000 }" ]
|
||||
```
|
||||
**Rosso.** Ripristinato dal backup.
|
||||
|
||||
**2. Colore-giudizio su una classe del macro-score.** Iniettato `color: #cc0000;` in
|
||||
`.lg-macro__nota`:
|
||||
```
|
||||
npm test -- tests/longevity/pagine.test.ts
|
||||
```
|
||||
```
|
||||
❯ ... in tutto il foglio compaiono solo i colori ammessi, salvo le eccezioni dichiarate
|
||||
AssertionError: expected [ Array(1) ] to deeply equal []
|
||||
+ [ ".lg-macro__nota { color: #cc0000 }" ]
|
||||
```
|
||||
**Rosso.** Ripristinato dal backup (`diff` col backup: nessuna differenza).
|
||||
|
||||
Rilanciato dopo il secondo ripristino:
|
||||
```
|
||||
npm test -- tests/longevity/pagine.test.ts
|
||||
```
|
||||
```
|
||||
Test Files 1 passed (1)
|
||||
Tests 6 passed (6)
|
||||
```
|
||||
**Verde.** Entrambe le classi (radar e macro-score) sono ora sorvegliate — nessun buco
|
||||
residuo fra le due superfici nuove di questo task.
|
||||
|
||||
### Verifiche finali
|
||||
|
||||
```
|
||||
npm test
|
||||
```
|
||||
```
|
||||
Test Files 1 failed | 39 passed (40)
|
||||
Tests 1 failed | 327 passed (328)
|
||||
```
|
||||
Stesso rosso pre-esistente e fuori perimetro (`tests/modifiche-agosto.test.ts > ...
|
||||
inaugurazione ...`); nessuna regressione.
|
||||
|
||||
```
|
||||
npx tsc --noEmit
|
||||
```
|
||||
Output: nessuno (pulito).
|
||||
|
||||
### Commit
|
||||
|
||||
```
|
||||
git add tests/longevity/pagine.test.ts
|
||||
git commit -m "longevity: il controllo sui colori guarda tutto il foglio, non solo lg-score"
|
||||
```
|
||||
```
|
||||
[feat/longevity a56398e] longevity: il controllo sui colori guarda tutto il foglio, non solo lg-score
|
||||
1 file changed, 23 insertions(+), 5 deletions(-)
|
||||
```
|
||||
`git status` dopo il commit: albero pulito.
|
||||
Reference in New Issue
Block a user