test: le sei tabelle dei sollevamenti sorvegliate, e il caso misto

- motore-fisici.test.ts confrontava i tiers letti dal file di
  riferimento, non le costanti TIERS_* del codice: ventiquattro numeri
  senza custode. Ora identifica la tabella dagli argomenti
  dell'oracolo ma usa le costanti vere per calcolare, quindi una
  costante alterata non combacia più con nessun caso.
- motore-caso-reale.test.ts: aggiunto il caso end-to-end mancante, un
  asse valido (Composizione Corporea, via due righe aggiunte al
  registro) e sei insufficienti — oggi la suite copriva solo "tutto
  insufficiente".
- test-fisici.ts: commento in testa che dichiara le venti curve non
  collegate al motore (vocabolario delle curve senza nomi per loro,
  applicaCurva senza modo di ricevere età/sesso) — aggancio è lavoro
  del piano degli import, non "una modifica ai dati" come la spec
  lascia intendere.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XhLbMQ1q7wHwJSykgXRwQF
This commit is contained in:
2026-08-22 10:49:35 +02:00
parent 469251366e
commit c1c868622f
3 changed files with 76 additions and 11 deletions
+35
View File
@@ -43,4 +43,39 @@ describe('un profilo con una sola area misurata', () => {
}
}
});
/**
* Il caso misto: quello che la prima dashboard disegnera' davvero, non "tutto
* insufficiente". Realizza per intero la premessa del describe qui sopra — la
* composizione corporea davvero misurata dalla Wellness Tower — aggiungendo le
* due voci al registro (arrivano col piano degli import; qui bastano due righe,
* non serve aspettarle) e registrando le misure end-to-end.
*/
it('un asse valido (Composizione Corporea) e sei insufficienti, end-to-end', () => {
const db = createLongevityDb(':memory:');
seedRegistro(db);
seedPesi(db, MODEL_VERSION);
db.prepare(`INSERT INTO soggetti (client_code, sesso) VALUES ('ISL-0003','M')`).run();
db.prepare(
`INSERT INTO registro_test (test_id, etichetta, tipo_valore, curva, params, asse, sotto_dominio, attivo_da)
VALUES ('wt_grasso', 'Grasso % (Wellness Tower)', 'num', 'lin_dec', ?, 'Composizione Corporea', 'grasso', '2026-01-01')`
).run(JSON.stringify({ best: 10, worst: 40 }));
db.prepare(
`INSERT INTO registro_test (test_id, etichetta, tipo_valore, curva, params, asse, sotto_dominio, attivo_da)
VALUES ('wt_muscolo', 'Muscolo % (Wellness Tower)', 'num', 'lin_dec', ?, 'Composizione Corporea', 'muscolo', '2026-01-01')`
).run(JSON.stringify({ best: 50, worst: 30 }));
const s = apriSessione(db, { client_code: 'ISL-0003', data: '2026-08-22', tipo: 'checkup', eta_alla_data: 38 });
registraMisure(db, s, 'wellness_tower', [
{ test_id: 'wt_grasso', valore_num: 15 },
{ test_id: 'wt_muscolo', valore_num: 45 },
]);
const r = calcolaSessione(db, s);
expect(r.assi['Composizione Corporea'].stato).toBe('ok');
const insufficienti = Object.entries(r.assi)
.filter(([nome, a]) => nome !== 'Composizione Corporea' && a.stato === 'insufficiente');
expect(insufficienti.length).toBe(6);
});
});
+28 -11
View File
@@ -47,21 +47,38 @@ describe('curve dei test fisici, confrontate con l oracolo caso per caso', () =>
});
}
it('i sollevamenti sul peso corporeo combaciano su tutte e tre le tabelle', () => {
it('i sollevamenti sul peso corporeo combaciano su tutte e tre le tabelle DEFINITE NEL CODICE', () => {
// Prima versione di questo test: passava alla funzione le tabelle lette dagli
// argomenti del riferimento (c.args), non le costanti TIERS_* definite nel
// codice — le sei tabelle non erano confrontate contro l'oracolo da nessuno.
// Qui si usano SOLO le costanti del modulo: se una venisse alterata, nessun
// caso combacerebbe piu' con gli argomenti del riferimento e il test cade.
const casi = RIF.casi.filter((c) => c.fn === 'score_bw_ratio_lift');
expect(casi.length).toBeGreaterThan(50);
const perTabella = (nome: string) =>
({ bench: [F.TIERS_BENCH_M, F.TIERS_BENCH_F], squat: [F.TIERS_SQUAT_M, F.TIERS_SQUAT_F],
row: [F.TIERS_ROW_M, F.TIERS_ROW_F] } as Record<string, unknown[]>)[nome];
const TABELLE: [string, [number, number][], [number, number][]][] = [
['bench', F.TIERS_BENCH_M, F.TIERS_BENCH_F],
['squat', F.TIERS_SQUAT_M, F.TIERS_SQUAT_F],
['row', F.TIERS_ROW_M, F.TIERS_ROW_F],
];
const perTabella: Record<string, number> = { bench: 0, squat: 0, row: 0 };
for (const c of casi) {
const [carico, peso, rip, tiersM, tiersF, sesso] = c.args as [number, number, number, unknown, unknown, 'M' | 'F'];
const ottenuto = F.scoreSollevamentoSuPeso(
carico, peso, rip,
tiersM as [number, number][], tiersF as [number, number][], sesso
);
expect(ottenuto, `carico ${carico} ${sesso}`).toBeCloseTo(c.atteso, 1);
const [carico, peso, rip, tiersMRif, , sesso] = c.args as [number, number, number, unknown, unknown, 'M' | 'F'];
// Identifica QUALE tabella del codice questo caso sta esercitando confrontando
// gli argomenti del riferimento con le costanti vere — non il contrario.
const trovata = TABELLE.find(([, tm]) => JSON.stringify(tm) === JSON.stringify(tiersMRif));
expect(trovata, `nessuna tabella del codice combacia con gli argomenti del caso: carico ${carico} ${sesso}`).toBeDefined();
const [nome, tiersM, tiersF] = trovata!;
perTabella[nome]++;
const ottenuto = F.scoreSollevamentoSuPeso(carico, peso, rip, tiersM, tiersF, sesso);
expect(ottenuto, `${nome} carico ${carico} ${sesso}`).toBeCloseTo(c.atteso, 1);
}
expect(perTabella('bench')).toBeTruthy();
// Tutte e tre le tabelle sono state esercitate davvero, non solo dichiarate.
expect(perTabella.bench).toBeGreaterThan(0);
expect(perTabella.squat).toBeGreaterThan(0);
expect(perTabella.row).toBeGreaterThan(0);
});
it('le due funzioni escluse dal porting non esistono nel modulo', () => {