[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
|
|
|
|
// © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
|
|
|
|
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
|
|
|
|
|
|
|
|
|
|
|
// La génération (§ 5.7, § 5.8, § 5.10) : les exécuteurs qui font tourner la
|
|
|
|
|
|
// recherche du moteur, et le contrôleur qui la lance depuis la séance.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Un exécuteur rend, pour une configuration et des réglages, une exécution :
|
|
|
|
|
|
// son résultat, une promesse des propositions de rechercher ; ses
|
|
|
|
|
|
// avancements ; son annulation, qui rejette le résultat par ErreurAnnulee,
|
|
|
|
|
|
// sans résultat partiel. L'exécuteur direct calcule dans le fil, une
|
|
|
|
|
|
// microtâche après le lancement : il sert les épreuves et le premier
|
|
|
|
|
|
// montage de l'application ; celui du travailleur (I13) calcule hors du fil
|
|
|
|
|
|
// et s'annule par terminate(). Une erreur de la recherche devient la même
|
|
|
|
|
|
// dans les deux, par versErreurGeneration.
|
|
|
|
|
|
//
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
// Le contrôleur tient aussi le réglage des cœurs de calcul, un réglage du
|
|
|
|
|
|
// poste qui vaut pour la séance de l'application et ne s'écrit nulle part :
|
|
|
|
|
|
// automatique, la génération emploie autant de cœurs que l'exécuteur annonce
|
|
|
|
|
|
// de processeurs logiques (coeursDisponibles, que src/main.js lit de la
|
|
|
|
|
|
// plateforme) ; sinon le nombre saisi, de 1 à ces disponibles. Un lancement
|
|
|
|
|
|
// en emploie min(nombre de propositions, cœurs réglés), et l'estimation
|
|
|
|
|
|
// compte en vagues de propositions calculées ensemble.
|
|
|
|
|
|
//
|
[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
|
|
|
|
// Le contrôleur ne numérote rien et ne mesure aucun plan. Il refuse avant
|
|
|
|
|
|
// tout lancement un réglage hors de son domaine (REGLAGE_HORS_DOMAINE), puis
|
|
|
|
|
|
// ce que l'enregistrement refuserait — les refus de la séance, lus dans son
|
|
|
|
|
|
// état observable, dans l'ordre de son contrat —, puis
|
|
|
|
|
|
// ce qui rend la génération vaine ou impossible ; il garde la graine
|
|
|
|
|
|
// proposée et la durée du dernier calcul, en mémoire, pour la séance de
|
|
|
|
|
|
// l'application ; il vérifie les invariants de chaque proposition rendue,
|
|
|
|
|
|
// écarte celles dont le plan est déjà présent, et confie les autres à la
|
|
|
|
|
|
// commande enregistrerGeneration, une seule entrée du journal. Le nombre de
|
|
|
|
|
|
// propositions d'une génération est un réglage, jamais une constante d'ici.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Le compte d'inactivité de la séance est suspendu pendant toute la
|
|
|
|
|
|
// génération (debuterCalcul), et repart à sa fin, quelle qu'elle soit
|
|
|
|
|
|
// (finirCalcul, dans un finally). Passer en lecture, ou fermer l'événement,
|
|
|
|
|
|
// annule la génération en cours (surAnnulation).
|
|
|
|
|
|
import { normaliser, nombrePlacesManquantes } from '../moteur/configuration.js';
|
|
|
|
|
|
import { ErreurAnnulee, ErreurConfiguration } from '../moteur/erreurs.js';
|
|
|
|
|
|
import { rechercher, verifierReglages } from '../moteur/recherche.js';
|
|
|
|
|
|
import { verifierInvariants } from '../moteur/verification.js';
|
|
|
|
|
|
import { GENERATION_PAR_DEFAUT, configurationDepuisCharge } from '../stockage/document.js';
|
|
|
|
|
|
import { derive, planDepuisFichier, versFichier } from '../stockage/placements.js';
|
|
|
|
|
|
import { lireEntier } from './capacite.js';
|
|
|
|
|
|
|
|
|
|
|
|
// src/interface reçoit l'annulation d'ici : elle ne joint pas le moteur.
|
|
|
|
|
|
export { ErreurAnnulee } from '../moteur/erreurs.js';
|
|
|
|
|
|
|
|
|
|
|
|
/** Au-delà de cette durée estimée, en secondes, la génération demande confirmation (§ 5.10). */
|
|
|
|
|
|
export const SEUIL_GENERATION_LONGUE_S = 60;
|
|
|
|
|
|
|
|
|
|
|
|
/** Le plafond d'usage d'une génération, en secondes (§ 5.10) : un repère dit, jamais un refus. */
|
|
|
|
|
|
export const PLAFOND_USAGE_S = 30 * 60;
|
|
|
|
|
|
|
|
|
|
|
|
// Sans durée mesurée, une génération de plus de mouvements que ce compte —
|
|
|
|
|
|
// dix fois le réglage par défaut — demande confirmation.
|
|
|
|
|
|
const MOUVEMENTS_SANS_MESURE = 10 * GENERATION_PAR_DEFAUT.nombre * GENERATION_PAR_DEFAUT.arret;
|
|
|
|
|
|
|
|
|
|
|
|
// La plus grande graine, et le modulo de la suivante.
|
|
|
|
|
|
const GRAINE_MAX = 2 ** 32 - 1;
|
|
|
|
|
|
const GRAINES = 2 ** 32;
|
|
|
|
|
|
|
|
|
|
|
|
// Les champs des réglages, dans l'ordre où leurs refus se rendent, et le
|
|
|
|
|
|
// domaine de chacun ; max null : sans borne.
|
|
|
|
|
|
const CHAMPS = [
|
|
|
|
|
|
['graine', 0, GRAINE_MAX],
|
|
|
|
|
|
['nombre', 1, null],
|
|
|
|
|
|
['arret', 1, null],
|
|
|
|
|
|
['historique', 1, null],
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
const versSection = (section) => ({ geste: 'ouvrirSection', section });
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Refus ou échec d'une génération : son code et ses détails — ceux de la
|
|
|
|
|
|
* séance, du moteur ou du contrôleur, tels quels. Le texte affiché est celui
|
|
|
|
|
|
* de son code, nu (§ 14.6) ; le message, code et détails en JSON, sert aux
|
|
|
|
|
|
* traces.
|
|
|
|
|
|
*/
|
|
|
|
|
|
export class ErreurGeneration extends Error {
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @param {string} code
|
|
|
|
|
|
* @param {Object} [details]
|
|
|
|
|
|
*/
|
|
|
|
|
|
constructor(code, details = {}) {
|
|
|
|
|
|
super(`${code} ${JSON.stringify(details)}`);
|
|
|
|
|
|
this.code = code;
|
|
|
|
|
|
this.details = details;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
ErreurGeneration.prototype.name = 'ErreurGeneration';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Les réglages d'une génération, contrôlés par la règle de rechercher
|
|
|
|
|
|
* (verifierReglages) avant tout calcul. Lève, pour le premier réglage hors
|
|
|
|
|
|
* de son domaine, ErreurGeneration('REGLAGE_HORS_DOMAINE', { reglage,
|
|
|
|
|
|
* remede: null }), reglage étant son nom — graine, arret, historique ou
|
|
|
|
|
|
* nombre —, sans le message du moteur ; ne rend rien sinon. Toute autre
|
|
|
|
|
|
* erreur du contrôle est relevée telle quelle.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param {Object} reglages
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function exigerReglages(reglages) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
verifierReglages(reglages);
|
|
|
|
|
|
} catch (erreur) {
|
|
|
|
|
|
if (erreur instanceof RangeError && typeof erreur.reglage === 'string') {
|
|
|
|
|
|
throw new ErreurGeneration('REGLAGE_HORS_DOMAINE', { reglage: erreur.reglage, remede: null });
|
|
|
|
|
|
}
|
|
|
|
|
|
throw erreur;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
/**
|
|
|
|
|
|
* Le nombre de processeurs logiques d'un poste, tel que la plateforme le
|
|
|
|
|
|
* donne — hyperthreads compris —, rendu utilisable : un entier d'au moins 1
|
|
|
|
|
|
* tel quel, 1 pour toute autre valeur, absente comprise.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param {unknown} valeur
|
|
|
|
|
|
* @returns {number}
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function coeursDe(valeur) {
|
|
|
|
|
|
return Number.isInteger(valeur) && valeur >= 1 ? valeur : 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
[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
|
|
|
|
/**
|
|
|
|
|
|
* L'erreur d'une recherche, la même dans les deux exécuteurs : ErreurAnnulee
|
|
|
|
|
|
* telle quelle ; une ErreurConfiguration devient ErreurGeneration de son code
|
|
|
|
|
|
* et de ses détails ; toute autre, RangeError comprise, est rendue telle
|
|
|
|
|
|
* quelle, pour être relevée. Les réglages sont contrôlés avant le calcul
|
|
|
|
|
|
* (exigerReglages) : une RangeError qui survient pendant lui vient d'ailleurs,
|
|
|
|
|
|
* d'un abonné aux avancements par exemple, et ne se dit pas comme un réglage.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param {unknown} erreur
|
|
|
|
|
|
* @returns {unknown}
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function versErreurGeneration(erreur) {
|
|
|
|
|
|
if (erreur instanceof ErreurAnnulee) return erreur;
|
|
|
|
|
|
if (erreur instanceof ErreurConfiguration) return new ErreurGeneration(erreur.code, erreur.details);
|
|
|
|
|
|
return erreur;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @typedef {Object} Execution
|
|
|
|
|
|
* @property {(fn: (fait: number, total: number) => void) => () => void} surAvancement
|
|
|
|
|
|
* abonne fn aux avancements ; rend la fonction qui désabonne
|
|
|
|
|
|
* @property {Promise<import('../moteur/recherche.js').Proposition[]>} resultat
|
|
|
|
|
|
* rejetée par ErreurAnnulee à l'annulation, par ErreurGeneration sur
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
* une erreur du moteur ; les propositions par identifiant croissant
|
[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
|
|
|
|
* @property {() => void} annuler sans résultat partiel
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
* @property {number} [coeurs] les cœurs que le calcul emploie ; 1 s'il
|
|
|
|
|
|
* ne le dit pas
|
[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
|
|
|
|
*
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
* @typedef {Object} Executeur
|
|
|
|
|
|
* @property {(configuration: Object, reglages: Object, options?: {coeurs?: number}) => Execution} lancer
|
|
|
|
|
|
* options.coeurs : les cœurs que le calcul peut employer, 1 par défaut
|
|
|
|
|
|
* @property {number} [coeursDisponibles] les processeurs logiques du poste ;
|
|
|
|
|
|
* 1 s'il ne le dit pas
|
[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
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* L'exécuteur direct : rechercher dans le fil, une microtâche après lancer.
|
|
|
|
|
|
* Rien d'autre ne s'exécute pendant la recherche. annuler(), avant ce départ
|
|
|
|
|
|
* ou depuis un rappel d'avancement, fait lever ErreurAnnulee à la lecture
|
|
|
|
|
|
* suivante du signal par le moteur : avant la proposition suivante, au plus
|
|
|
|
|
|
* 1 000 mouvements plus tard. Chaque avancement est celui du moteur, toutes
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
* les 1 000 itérations. Il calcule une proposition après l'autre quel que
|
|
|
|
|
|
* soit options.coeurs, et chaque exécution dit n'employer qu'un cœur ; il
|
|
|
|
|
|
* annonce les cœurs qu'on lui donne, par coeursDe, pour qu'une épreuve règle
|
|
|
|
|
|
* ce que le contrôleur en lit.
|
[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
|
|
|
|
*
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
* @param {{coeursDisponibles?: unknown}} [options]
|
[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
|
|
|
|
* @returns {Executeur}
|
|
|
|
|
|
*/
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
export function creerExecuteurDirect({ coeursDisponibles } = {}) {
|
[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
|
|
|
|
return {
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
coeursDisponibles: coeursDe(coeursDisponibles),
|
[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
|
|
|
|
lancer(configuration, reglages) {
|
|
|
|
|
|
const signal = { aborted: false };
|
|
|
|
|
|
const abonnes = new Set();
|
|
|
|
|
|
const progression = (fait, total) => {
|
|
|
|
|
|
for (const fn of [...abonnes]) fn(fait, total);
|
|
|
|
|
|
};
|
|
|
|
|
|
const resultat = Promise.resolve().then(() => {
|
|
|
|
|
|
exigerReglages(reglages);
|
|
|
|
|
|
try {
|
|
|
|
|
|
return rechercher(configuration, reglages, { signal, progression });
|
|
|
|
|
|
} catch (erreur) {
|
|
|
|
|
|
throw versErreurGeneration(erreur);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
return {
|
|
|
|
|
|
surAvancement(fn) {
|
|
|
|
|
|
abonnes.add(fn);
|
|
|
|
|
|
return () => {
|
|
|
|
|
|
abonnes.delete(fn);
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
resultat,
|
|
|
|
|
|
annuler() {
|
|
|
|
|
|
signal.aborted = true;
|
|
|
|
|
|
},
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
coeurs: 1,
|
[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
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Le plan d'une proposition du moteur, rangé comme planDepuisFichier rend
|
|
|
|
|
|
// celui d'une proposition enregistrée : la même mise en forme, versFichier
|
|
|
|
|
|
// puis planDepuisFichier, pour que deux plans égaux s'écrivent pareil.
|
|
|
|
|
|
function planRange(proposition, configuration, produitVersion) {
|
|
|
|
|
|
const fichier = versFichier(proposition, configuration, { produitVersion, attribuerSieges: false, decalage: 0 });
|
|
|
|
|
|
return JSON.stringify(planDepuisFichier(fichier));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Le contrôleur de génération d'une séance (§ 5.7, § 5.10).
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param {Object} parametres
|
|
|
|
|
|
* @param {Object} parametres.seance la séance d'A1 et A2 : etat,
|
|
|
|
|
|
* subscribe, surAnnulation, executer, debuterCalcul, finirCalcul
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
* @param {Executeur} parametres.executeur coeursDisponibles, qu'il annonce,
|
|
|
|
|
|
* borne le réglage des cœurs
|
[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
|
|
|
|
* @param {import('./horloge.js').Horloge} parametres.horloge instant() mesure
|
|
|
|
|
|
* la durée d'un calcul
|
|
|
|
|
|
* @param {string} parametres.produitVersion
|
|
|
|
|
|
* @returns {Object} le contrôleur : grainePropose, reglagesProposes, valider,
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
* estimer, derniereGeneration, generer, annuler, coeurs,
|
|
|
|
|
|
* reglerCoeurs, subscribe
|
[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
|
|
|
|
*/
|
|
|
|
|
|
export function creerControleurGeneration({ seance, executeur, horloge, produitVersion }) {
|
|
|
|
|
|
// graine : la graine proposée ; base : celle de l'événement ouvert, null
|
|
|
|
|
|
// sans événement ; mesure : le dernier calcul abouti, null avant lui ;
|
|
|
|
|
|
// execution : celle en cours, null hors génération ; enCours vaut vrai du
|
|
|
|
|
|
// lancement à la fin de l'enregistrement.
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
// coeurs : le réglage des cœurs de calcul, que l'observable porte —
|
|
|
|
|
|
// automatique, le nombre saisi (manuel), les disponibles, et nombre, les
|
|
|
|
|
|
// cœurs réglés.
|
[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
|
|
|
|
let graine = 1;
|
|
|
|
|
|
let base = null;
|
|
|
|
|
|
let mesure = null;
|
|
|
|
|
|
let execution = null;
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
const disponibles = coeursDe(executeur.coeursDisponibles);
|
|
|
|
|
|
let reglageCoeurs = { automatique: true, manuel: disponibles };
|
|
|
|
|
|
const coeurs = () => ({
|
|
|
|
|
|
...reglageCoeurs,
|
|
|
|
|
|
disponibles,
|
|
|
|
|
|
nombre: reglageCoeurs.automatique ? disponibles : reglageCoeurs.manuel,
|
|
|
|
|
|
});
|
|
|
|
|
|
let observable = { enCours: false, fait: 0, total: 0, annulee: null, coeurs: coeurs() };
|
[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
|
|
|
|
const abonnes = new Set();
|
|
|
|
|
|
|
|
|
|
|
|
function publier(changements) {
|
|
|
|
|
|
observable = { ...observable, ...changements };
|
|
|
|
|
|
for (const fn of [...abonnes]) fn(observable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Une ouverture : l'événement passe de null, ou d'une autre base, à une
|
|
|
|
|
|
// base ; la graine proposée repart de 1.
|
|
|
|
|
|
seance.subscribe((etat) => {
|
|
|
|
|
|
const suivante = etat.evenement?.base ?? null;
|
|
|
|
|
|
if (suivante !== null && suivante !== base) graine = 1;
|
|
|
|
|
|
base = suivante;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Les réglages de génération de la charge ouverte, ceux d'une charge
|
|
|
|
|
|
// neuve sans événement.
|
|
|
|
|
|
const reglagesDeLaCharge = () => seance.etat().charge?.reglages.generation ?? GENERATION_PAR_DEFAUT;
|
|
|
|
|
|
|
|
|
|
|
|
function annulerAvec(cause) {
|
|
|
|
|
|
if (execution === null) return;
|
|
|
|
|
|
const courante = execution;
|
|
|
|
|
|
publier({ annulee: cause });
|
|
|
|
|
|
courante.annuler();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
// Les cœurs qu'un lancement de nombre propositions emploie.
|
|
|
|
|
|
const coeursPour = (nombre) => Math.min(nombre, coeurs().nombre);
|
|
|
|
|
|
|
|
|
|
|
|
// Les mouvements d'une génération qui se suivent sur un même cœur : arret
|
|
|
|
|
|
// pour chacune des ⌈nombre / cœurs⌉ vagues de propositions calculées
|
|
|
|
|
|
// ensemble.
|
|
|
|
|
|
const mouvementsParCoeur = (nombre, arret, parallele) => Math.ceil(nombre / parallele) * arret;
|
|
|
|
|
|
|
|
|
|
|
|
// La durée d'une génération, proportionnelle aux mouvements qui se suivent
|
|
|
|
|
|
// sur un même cœur, ceux de la mesure ramenés aux cœurs qu'elle a employés.
|
[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
|
|
|
|
function estimer({ nombre, arret }) {
|
|
|
|
|
|
if (mesure === null) return { inconnue: true };
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
const parallele = coeursPour(nombre);
|
|
|
|
|
|
const secondes =
|
|
|
|
|
|
(mouvementsParCoeur(nombre, arret, parallele) * mesure.dureeMs) /
|
|
|
|
|
|
(mouvementsParCoeur(mesure.nombre, mesure.arret, mesure.coeurs) * 1000);
|
[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
|
|
|
|
return {
|
|
|
|
|
|
secondes,
|
|
|
|
|
|
longue: secondes > SEUIL_GENERATION_LONGUE_S,
|
|
|
|
|
|
auDelaDuPlafond: secondes > PLAFOND_USAGE_S,
|
|
|
|
|
|
mesure: { ...mesure },
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
coeurs: parallele,
|
[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
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
// Longue : au-delà du seuil estimé, ou, sans mesure, quand les mouvements
|
|
|
|
|
|
// qui se suivent sur un même cœur dépassent dix fois le réglage par défaut.
|
[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
|
|
|
|
function estLongue(reglages, estimation) {
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
if (estimation.inconnue === true) {
|
|
|
|
|
|
return mouvementsParCoeur(reglages.nombre, reglages.arret, coeursPour(reglages.nombre)) > MOUVEMENTS_SANS_MESURE;
|
|
|
|
|
|
}
|
[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
|
|
|
|
return estimation.longue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Les refus d'avant lancement : les réglages d'abord, puis l'ordre du
|
|
|
|
|
|
// contrat ; rend la configuration et son instance quand la génération peut
|
|
|
|
|
|
// partir.
|
|
|
|
|
|
function exigerLancement(reglages, confirmee) {
|
|
|
|
|
|
exigerReglages(reglages);
|
|
|
|
|
|
const etat = seance.etat();
|
|
|
|
|
|
if (etat.evenement === null) throw new ErreurGeneration('AUCUN_EVENEMENT', { remede: null });
|
|
|
|
|
|
if (etat.refus !== null) throw new ErreurGeneration(etat.refus.code, etat.refus.details);
|
|
|
|
|
|
if (execution !== null || observable.enCours) throw new ErreurGeneration('GENERATION_EN_COURS', { remede: null });
|
|
|
|
|
|
const { charge } = etat;
|
|
|
|
|
|
if (!charge.participants.some(({ exclu }) => !exclu)) {
|
|
|
|
|
|
throw new ErreurGeneration('AUCUN_PARTICIPANT', { remede: versSection('participants') });
|
|
|
|
|
|
}
|
|
|
|
|
|
if (charge.tables.length === 0) throw new ErreurGeneration('AUCUNE_TABLE', { remede: versSection('tables') });
|
|
|
|
|
|
const configuration = configurationDepuisCharge(charge);
|
|
|
|
|
|
let instance;
|
|
|
|
|
|
try {
|
|
|
|
|
|
instance = normaliser(configuration);
|
|
|
|
|
|
} catch (erreur) {
|
|
|
|
|
|
if (erreur instanceof ErreurConfiguration) throw new ErreurGeneration(erreur.code, { ...erreur.details, remede: null });
|
|
|
|
|
|
throw erreur;
|
|
|
|
|
|
}
|
|
|
|
|
|
const placesManquantes = nombrePlacesManquantes(instance);
|
|
|
|
|
|
if (placesManquantes > 0) {
|
|
|
|
|
|
throw new ErreurGeneration('PLACES_MANQUANTES', { placesManquantes, remede: versSection('tables') });
|
|
|
|
|
|
}
|
|
|
|
|
|
const estimation = estimer(reglages);
|
|
|
|
|
|
if (!confirmee && estLongue(reglages, estimation)) {
|
|
|
|
|
|
throw new ErreurGeneration('CONFIRMATION_REQUISE', { estimation, remede: null });
|
|
|
|
|
|
}
|
|
|
|
|
|
return { configuration, instance };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Le calcul confié à l'exécuteur : ses avancements publiés, son annulation
|
|
|
|
|
|
// par la séance suivie ; rend les propositions et la durée du calcul. Une
|
|
|
|
|
|
// annulation lève ErreurAnnulee, même quand l'exécuteur a rendu un
|
|
|
|
|
|
// résultat entre-temps.
|
|
|
|
|
|
async function calculer(configuration, reglages) {
|
|
|
|
|
|
const debut = horloge.instant();
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
execution = executeur.lancer(configuration, reglages, { coeurs: coeursPour(reglages.nombre) });
|
|
|
|
|
|
const employes = coeursDe(execution.coeurs);
|
[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
|
|
|
|
const desabonner = execution.surAvancement((fait, total) => publier({ fait, total }));
|
|
|
|
|
|
const desannuler = seance.surAnnulation(() => annulerAvec('seance'));
|
|
|
|
|
|
try {
|
|
|
|
|
|
const propositions = await execution.resultat;
|
|
|
|
|
|
if (observable.annulee !== null) throw new ErreurAnnulee();
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
return { propositions, dureeMs: horloge.instant() - debut, coeurs: employes };
|
[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
|
|
|
|
} finally {
|
|
|
|
|
|
desabonner();
|
|
|
|
|
|
desannuler();
|
|
|
|
|
|
execution = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Les propositions à enregistrer, par identifiant du moteur croissant :
|
|
|
|
|
|
// chacune sans violation des invariants, sinon GENERATION_INVARIANT_VIOLE,
|
|
|
|
|
|
// rang compris — la place de la proposition dans la suite des graines du
|
|
|
|
|
|
// lancement, qui n'est l'identifiant d'aucune proposition enregistrée ; puis sans
|
|
|
|
|
|
// celles dont le plan est celui d'une proposition présente sans dérive, ou
|
|
|
|
|
|
// d'une proposition déjà gardée de ce lancement.
|
|
|
|
|
|
function trier(propositions, configuration, instance) {
|
|
|
|
|
|
const ordonnees = [...propositions].sort((a, b) => a.id - b.id);
|
|
|
|
|
|
for (const proposition of ordonnees) {
|
|
|
|
|
|
const violations = verifierInvariants(instance, proposition.plan);
|
|
|
|
|
|
if (violations.length > 0) {
|
|
|
|
|
|
throw new ErreurGeneration('GENERATION_INVARIANT_VIOLE', { rang: proposition.id, violations, remede: null });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
const charge = seance.etat().charge;
|
|
|
|
|
|
const presents = new Set(
|
|
|
|
|
|
charge.propositions.filter((p) => derive(p, charge).length === 0).map((p) => JSON.stringify(planDepuisFichier(p))),
|
|
|
|
|
|
);
|
|
|
|
|
|
const gardees = [];
|
|
|
|
|
|
for (const proposition of ordonnees) {
|
|
|
|
|
|
const plan = planRange(proposition, configuration, produitVersion);
|
|
|
|
|
|
if (presents.has(plan)) continue;
|
|
|
|
|
|
presents.add(plan);
|
|
|
|
|
|
gardees.push(proposition);
|
|
|
|
|
|
}
|
|
|
|
|
|
return { gardees, identiques: ordonnees.length - gardees.length };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Les identifiants que l'enregistrement a donnés : ceux des propositions
|
|
|
|
|
|
// de la charge qui n'étaient pas avant le geste, et qui portent la graine,
|
|
|
|
|
|
// l'arrêt et l'historique d'une proposition gardée ; croissants.
|
|
|
|
|
|
function ajouteesDans(charge, avant, gardees) {
|
|
|
|
|
|
const cles = new Set(gardees.map(({ graine: g, arret, historique }) => `${g}|${arret}|${historique}`));
|
|
|
|
|
|
return charge.propositions
|
|
|
|
|
|
.filter(({ id, graine: g, arret, historique }) => !avant.has(id) && cles.has(`${g}|${arret}|${historique}`))
|
|
|
|
|
|
.map(({ id }) => id)
|
|
|
|
|
|
.sort((a, b) => a - b);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function generer(reglages, { confirmee = false } = {}) {
|
|
|
|
|
|
const { configuration, instance } = exigerLancement(reglages, confirmee);
|
|
|
|
|
|
graine = (reglages.graine + 1) % GRAINES;
|
|
|
|
|
|
publier({ enCours: true, fait: 0, total: reglages.nombre * reglages.arret, annulee: null });
|
|
|
|
|
|
seance.debuterCalcul();
|
|
|
|
|
|
try {
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
const { propositions, dureeMs, coeurs: employes } = await calculer(configuration, reglages);
|
[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
|
|
|
|
mesure = {
|
|
|
|
|
|
dureeMs,
|
|
|
|
|
|
mouvements: reglages.nombre * reglages.arret,
|
|
|
|
|
|
participants: instance.N,
|
|
|
|
|
|
nombre: reglages.nombre,
|
|
|
|
|
|
arret: reglages.arret,
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
coeurs: employes,
|
[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
|
|
|
|
};
|
|
|
|
|
|
const { gardees, identiques } = trier(propositions, configuration, instance);
|
|
|
|
|
|
if (gardees.length === 0) return { ajoutees: [], identiques, dureeMs };
|
|
|
|
|
|
const avant = new Set(seance.etat().charge.propositions.map(({ id }) => id));
|
|
|
|
|
|
await seance.executer('enregistrerGeneration', { propositions: gardees, configuration, produitVersion });
|
|
|
|
|
|
return { ajoutees: ajouteesDans(seance.etat().charge, avant, gardees), identiques, dureeMs };
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
seance.finirCalcul();
|
|
|
|
|
|
publier({ enCours: false });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
/** La graine proposée : 1 à chaque ouverture, puis la dernière lancée plus un, modulo 2^32. */
|
|
|
|
|
|
grainePropose: () => graine,
|
|
|
|
|
|
/** { graine, nombre, arret, historique } : la graine proposée, les trois autres de la charge. */
|
|
|
|
|
|
reglagesProposes() {
|
|
|
|
|
|
const { nombre, arret, historique } = reglagesDeLaCharge();
|
|
|
|
|
|
return { graine, nombre, arret, historique };
|
|
|
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Les saisies des quatre champs, chacune lue par lireEntier (NON_ENTIER
|
|
|
|
|
|
* {saisie}), puis bornée à son domaine (HORS_DOMAINE {min, max}, max null
|
|
|
|
|
|
* sans borne) ; un historique non saisi — absent, null ou blanc — vaut
|
|
|
|
|
|
* celui de la charge. Rend { reglages, refus } : reglages null dès
|
|
|
|
|
|
* qu'un champ est refusé, refus dans l'ordre des champs.
|
|
|
|
|
|
*/
|
|
|
|
|
|
valider(saisies) {
|
|
|
|
|
|
const reglages = {};
|
|
|
|
|
|
const refus = [];
|
|
|
|
|
|
for (const [champ, min, max] of CHAMPS) {
|
|
|
|
|
|
const saisie = saisies[champ];
|
|
|
|
|
|
if (champ === 'historique' && (saisie === undefined || saisie === null || (typeof saisie === 'string' && saisie.trim() === ''))) {
|
|
|
|
|
|
reglages.historique = reglagesDeLaCharge().historique;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
const lu = lireEntier(saisie);
|
|
|
|
|
|
if (lu.refus !== undefined) {
|
|
|
|
|
|
refus.push({ champ, code: lu.refus.code, details: lu.refus.details });
|
|
|
|
|
|
} else if (lu.valeur < min || (max !== null && lu.valeur > max)) {
|
|
|
|
|
|
refus.push({ champ, code: 'HORS_DOMAINE', details: { min, max, remede: null } });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
reglages[champ] = lu.valeur;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return { reglages: refus.length === 0 ? reglages : null, refus };
|
|
|
|
|
|
},
|
|
|
|
|
|
/**
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
* L'estimation des réglages, proportionnelle aux mouvements qui se
|
|
|
|
|
|
* suivent sur un même cœur — arret × ⌈nombre / cœurs⌉ —, ceux de la
|
|
|
|
|
|
* dernière mesure ramenés de même aux cœurs qu'elle a employés :
|
|
|
|
|
|
* { inconnue: true } sans elle, sinon { secondes, longue,
|
|
|
|
|
|
* auDelaDuPlafond, mesure, coeurs }, coeurs étant ceux que ces réglages
|
|
|
|
|
|
* emploieraient.
|
[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
|
|
|
|
*/
|
|
|
|
|
|
estimer,
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
/**
|
|
|
|
|
|
* La mesure du dernier calcul abouti de ce contrôleur, en mémoire ; null
|
|
|
|
|
|
* avant lui : { dureeMs, mouvements, participants, nombre, arret,
|
|
|
|
|
|
* coeurs }, coeurs étant ceux que l'exécution a employés.
|
|
|
|
|
|
*/
|
[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
|
|
|
|
derniereGeneration: () => (mesure === null ? null : { ...mesure }),
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Lance une génération et l'enregistre : { ajoutees, identiques, dureeMs }.
|
|
|
|
|
|
* Refuse avant tout lancement, par ErreurGeneration, dans cet ordre :
|
|
|
|
|
|
* REGLAGE_HORS_DOMAINE {reglage} ; AUCUN_EVENEMENT ; le refus courant de
|
|
|
|
|
|
* la séance ; GENERATION_EN_COURS ;
|
|
|
|
|
|
* AUCUN_PARTICIPANT ; AUCUNE_TABLE ; le refus de normaliser ;
|
|
|
|
|
|
* PLACES_MANQUANTES ; CONFIRMATION_REQUISE {estimation}, que
|
|
|
|
|
|
* confirmee lève. Après la recherche : GENERATION_INVARIANT_VIOLE
|
|
|
|
|
|
* {rang, violations}, puis ce
|
|
|
|
|
|
* qu'executer lève, tel quel. Annulée : ErreurAnnulee.
|
|
|
|
|
|
*/
|
|
|
|
|
|
generer,
|
|
|
|
|
|
/** Annule la génération en cours, sans résultat partiel ; annulee vaut 'commande'. */
|
|
|
|
|
|
annuler: () => annulerAvec('commande'),
|
|
|
|
|
|
/**
|
[ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.
--- FR ---
[ADD] génération : réserve de travailleurs sur les processeurs, cœurs
La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.
Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
|
|
|
|
* Le réglage des cœurs de calcul : { automatique, manuel, disponibles,
|
|
|
|
|
|
* nombre } — automatique vrai à la création ; manuel, le dernier nombre
|
|
|
|
|
|
* saisi, les disponibles avant toute saisie ; disponibles, ceux
|
|
|
|
|
|
* qu'annonce l'exécuteur, par coeursDe ; nombre, les cœurs réglés,
|
|
|
|
|
|
* disponibles en automatique, manuel sinon.
|
|
|
|
|
|
*/
|
|
|
|
|
|
coeurs,
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Règle les cœurs de calcul, pour la séance de l'application : rien ne
|
|
|
|
|
|
* s'écrit, ni état, ni journal. saisie, quand elle est donnée, se lit
|
|
|
|
|
|
* par lireEntier (NON_ENTIER {saisie}), puis se borne de 1 aux
|
|
|
|
|
|
* disponibles (HORS_DOMAINE {min: 1, max}), remède null ; refusée, rien
|
|
|
|
|
|
* ne change, automatique compris. Rend { refus: null } ou { refus:
|
|
|
|
|
|
* {code, details} } ; un réglage accepté se publie aux abonnés.
|
|
|
|
|
|
*/
|
|
|
|
|
|
reglerCoeurs({ automatique, saisie } = {}) {
|
|
|
|
|
|
const suivant = { ...reglageCoeurs };
|
|
|
|
|
|
if (saisie !== undefined) {
|
|
|
|
|
|
const lu = lireEntier(saisie);
|
|
|
|
|
|
if (lu.refus !== undefined) return { refus: { code: lu.refus.code, details: lu.refus.details } };
|
|
|
|
|
|
if (lu.valeur < 1 || lu.valeur > disponibles) {
|
|
|
|
|
|
return { refus: { code: 'HORS_DOMAINE', details: { min: 1, max: disponibles, remede: null } } };
|
|
|
|
|
|
}
|
|
|
|
|
|
suivant.manuel = lu.valeur;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (automatique !== undefined) suivant.automatique = automatique === true;
|
|
|
|
|
|
reglageCoeurs = suivant;
|
|
|
|
|
|
publier({ coeurs: coeurs() });
|
|
|
|
|
|
return { refus: null };
|
|
|
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Le contrat des magasins de Svelte sur { enCours, fait, total, annulee,
|
|
|
|
|
|
* coeurs } : annulee, la cause de la dernière annulation, 'commande' ou
|
|
|
|
|
|
* 'seance', null dès le lancement suivant ; coeurs, le réglage des
|
|
|
|
|
|
* cœurs de calcul, celui que rend coeurs().
|
[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
|
|
|
|
*/
|
|
|
|
|
|
subscribe(fn) {
|
|
|
|
|
|
abonnes.add(fn);
|
|
|
|
|
|
fn(observable);
|
|
|
|
|
|
return () => {
|
|
|
|
|
|
abonnes.delete(fn);
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|