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
57 lines
2.8 KiB
JavaScript
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 });
|
|
};
|
|
}
|