batchCooking/apps/api/test-support/mocha-root-hooks.ts
Nicolas 1bf97ce6de fix(recipes): entraine le textcat plus longtemps pour une confiance reelle
Cause racine du dernier test Mocha en echec (getAuditBatch flaguait
"Faire mijoter a feu doux" comme peu fiable malgre une ancre NER claire) :
avec seulement 30 iterations/dropout 0.2, le textcat retournait le bon
intent (argmax correct) mais avec une confiance tres basse et compressee
(0.2-0.7 sur l'ensemble du corpus reel, y compris des cas evidents) —
un vrai probleme de qualite d'entrainement, pas seulement de seuil.

150 iterations / lot de 16 / dropout 0.1 (mesure localement contre le
vrai corpus, sans Postgres) : melt ~0.95, preheat ~0.90, jusqu'a ~0.51
pour le cas le plus faible observe (bake), bruit hors-vocabulaire toujours
~0.05. ~110s d'entrainement par locale (~220s pour fr+en au warm-up) —
compromis assume et documente (README du service, commentaires du code),
contrairement a l'entrainement quasi instantane de node-nlp.

Root hook Mocha (mocha-root-hooks.ts) et sa doc mis a jour avec un timeout
de 600s pour couvrir cette duree avec marge.

Verifie : 27/27 pytest, lint + build complets du monorepo. Suite Mocha a
confirmer sur ce commit via CI (source du diagnostic qui a mene a ce fix).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-25 21:00:48 +02:00

46 lines
2.7 KiB
TypeScript

import { techStepClassifier } from "../src/lib/recipe-matching/tech-step-matcher.js";
import { resetDatabase } from "./reset-db.js";
/**
* Mocha root hook plugin (see `.mocharc.json`'s `require`) — runs once
* before every test file's own suites, regardless of load order.
*
* Warms up `techStepClassifier` here, with its own generous timeout,
* instead of leaving it to happen lazily on whichever test file Mocha
* happens to load first. In production this one-time cost (a `POST
* /v1/train` round-trip per locale to `services/tech-step-intent-service`,
* training a real `textcat` on the full `TECH_STEP_TRAINING_DATA` corpus)
* is paid by `server.ts`'s own `techStepClassifier.warmUp()` before the
* server ever accepts traffic — but this test suite builds its `app`
* directly via `createApp()` (see e.g. `tech-step-worker.routes.test.ts`),
* never running `server.ts` at all. Without this hook, that cost instead
* landed inside whichever test's own call happened to trigger
* `_ensureTrained()` first — found the hard way in CI, where training the
* full corpus took longer than a single test's default 10s timeout
* (`.mocharc.json`) and failed an otherwise-unrelated test purely because
* Mocha loaded its file first alphabetically.
*
* `resetDatabase()` runs first, deliberately: `_train()`
* (`tech-step-matcher.ts`) resolves `TechStep.key -> id` from the database
* alongside training, and a freshly-migrated (never-seeded) test database
* has no `TechStep` rows yet — every per-test `beforeEach` in this suite
* already calls `resetDatabase()` again before its own test, which is a
* no-op duplication of effort but not a correctness problem: `TRUNCATE ...
* RESTART IDENTITY` plus deterministic re-seeding (`seedReferenceData`)
* assigns the exact same ids every time, so the `uid -> id` map memoized
* here from this first reset stays valid for every reset after it.
*/
export const mochaHooks = {
// biome-ignore lint/suspicious/noExplicitAny: Mocha's root hook `this` (a Context with `.timeout()`) isn't typed without @types/mocha (not a dependency here) — same untyped-`this` shape already used in tech-step-worker.routes.test.ts.
async beforeAll(this: any): Promise<void> {
// Generous on purpose: training both locales' `textcat` on the full
// corpus takes on the order of a couple of minutes combined (see
// `_TRAINING_ITERATIONS` in `services/tech-step-intent-service`'s
// `locale_pipeline.py`) — comfortably under 10 minutes even on a
// slower/contended CI runner, but nowhere near Mocha's normal 10s
// per-test default (`.mocharc.json`).
this.timeout(600000);
await resetDatabase();
await techStepClassifier.warmUp();
},
};