gestion_table_tournante_libre/src/application/generation_travailleur.js
Mathieu Benoit cc6b9fe996 [ADD] application: generation controller, worker, evaluation table
Generating must never block the screen or record a plan that breaks a
rule. The controller refuses before launching, in a fixed order: an
out-of-range setting named by the engine's own check, the session's
refusals, then what makes the run useless. It runs the search in a worker
or in the thread, records only propositions whose invariants hold, skips
plans already present, and keeps the last duration for the session only.
The evaluation table ranks propositions on the minimum of encounters and
names the reservations a proposition does not honour.
Checked: 2112 node and 60 node-long tests; coverage floors kept.

--- FR ---

[ADD] application : génération, travailleur, table d'évaluation

Générer ne doit jamais bloquer l'écran ni enregistrer un plan qui enfreint
une règle. Le contrôleur refuse avant tout lancement, dans un ordre fixe :
un réglage hors de son domaine, nommé par la règle même du moteur, les
refus de la séance, puis ce qui rend le calcul vain. Il lance la recherche
dans un travailleur ou dans le fil, n'enregistre que les propositions dont
les invariants tiennent, écarte les plans déjà présents, et garde la
dernière durée pour la seule séance. La table d'évaluation classe les
propositions sur le minimum de rencontres et nomme les réservations
qu'une proposition ne tient pas.
Vérifié : 2112 node et 60 node-long ; seuils de couverture tenus.

Assisted-by: Claude Opus 5.5
2026-10-07 06:09:45 -04:00

57 lines
2.8 KiB
JavaScript

// © 2026 TechnoLibre (http://www.technolibre.ca)
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
// Le côté travailleur de la génération (§ 5.10) : la recherche du moteur
// hors du fil de l'interface. Le travailleur reçoit un message, calcule, et
// poste ses avancements puis son résultat ou son erreur :
//
// → { type: 'lancer', configuration, reglages }
// ← { type: 'avancement', fait, total } au plus une fois toutes les
// CADENCE_AVANCEMENT progressions
// du moteur, fait croissant
// ← { type: 'resultat', propositions } celles de rechercher, telles quelles
// ← { type: 'erreur', code, details } REGLAGE_HORS_DOMAINE {reglage}
// d'exigerReglages, avant tout
// calcul ; puis, par
// versErreurGeneration, le code et
// les détails d'une
// ErreurConfiguration
//
// L'annulation est terminate() du côté de l'interface : immédiate, sans
// résultat partiel ; le travailleur ne lit aucun signal. Un message d'un
// autre type ne lance rien. Une erreur que versErreurGeneration ne convertit
// pas est relevée, et le travailleur la signale par son propre canal
// d'erreur.
import { rechercher } from '../moteur/recherche.js';
import { ErreurGeneration, exigerReglages, versErreurGeneration } from './generation.js';
/** Progressions du moteur — une toutes les 1 000 itérations — entre deux messages d'avancement. */
export const CADENCE_AVANCEMENT = 50;
/**
* Branche une portée de travailleur — { onmessage, postMessage } — sur
* rechercher, selon les messages de l'en-tête du module.
*
* @param {{onmessage: ((evenement: {data: unknown}) => void)|null, postMessage: (message: Object) => void}} portee
*/
export function brancherTravailleur(portee) {
portee.onmessage = ({ data }) => {
if (data === null || typeof data !== 'object' || data.type !== 'lancer') return;
let progressions = 0;
const progression = (fait, total) => {
progressions += 1;
if (progressions % CADENCE_AVANCEMENT === 0) portee.postMessage({ type: 'avancement', fait, total });
};
let propositions;
try {
exigerReglages(data.reglages);
propositions = rechercher(data.configuration, data.reglages, { progression });
} catch (erreur) {
const convertie = versErreurGeneration(erreur);
if (!(convertie instanceof ErreurGeneration)) throw convertie;
portee.postMessage({ type: 'erreur', code: convertie.code, details: convertie.details });
return;
}
portee.postMessage({ type: 'resultat', propositions });
};
}