[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 table d'évaluation (§ 5.4, § 5.5, § 5.7, § 12.6, § 13.2) : chaque
|
|
|
|
|
// proposition et le retenu, mesurés par la mesure qui fait foi, et le
|
|
|
|
|
// classement de celles qui se comparent. Le classement, les colonnes et le
|
|
|
|
|
// retenu la lisent ; ce module est le seul de l'application qui importe les
|
|
|
|
|
// mesures du moteur, et il n'en refait aucune.
|
|
|
|
|
//
|
|
|
|
|
// Un placement se compare quand il décrit la configuration courante : sans
|
|
|
|
|
// faute (fautes, S2) et sans dérive (derive, S2). Fautif ou en dérive, il
|
|
|
|
|
// n'est ni mesuré ni classé, et ses raisons disent pourquoi — la partition
|
|
|
|
|
// se fait avant classer, qui laisse passer deux populations de même taille.
|
[IMP] proposal evaluation: cached per frozen charge, validated once
The Génération and Propositions tabs re-evaluated every proposal on each
visit, about 1 ms per proposal, with no bound on how many accumulate.
The evaluation table is now kept per frozen event charge, which every
write replaces, and both tabs share it. Each placement is validated once
instead of three times; the public derive and planDepuisFichier still
validate, and a guard keeps the unchecked variants to evaluer alone.
At 200 proposals: Génération 214 to 17 ms on revisit, Propositions 310
to 118 ms. Checked: results deep-equal; node 4019, browser 873.
--- FR ---
[IMP] évaluation des propositions : gardée par charge, validée une fois
Les onglets Génération et Propositions réévaluaient toutes les
propositions à chaque visite, environ 1 ms chacune, sans borne sur leur
nombre. La table d'évaluation se garde par charge figée, qu'une écriture
remplace, et les deux onglets la partagent. Chaque placement se valide
une fois au lieu de trois ; derive et planDepuisFichier publics valident
toujours, une garde réserve les variantes sans contrôle à evaluer.
À 200 propositions : Génération 214 → 17 ms au retour, Propositions
310 → 118 ms. Vérifié : résultats identiques ; node 4019, nav. 873.
Assisted-by: Claude Opus 5.5
2026-10-11 03:43:47 -04:00
|
|
|
// evaluer valide chaque placement une fois, par fautes, puis lit le placement
|
|
|
|
|
// sans faute par deriveSansRevalider et planSansRevalider, qui ne refont pas
|
|
|
|
|
// cette validation : un placement fautif ne les atteint jamais, et c'est ce
|
|
|
|
|
// seul appel à fautes qui l'arrête. resumeDuRetenu passe par derive et
|
|
|
|
|
// planDepuisFichier, qui la refont et lèvent sur une faute.
|
[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
|
|
|
//
|
|
|
|
|
// Les imposés viennent du diagnostic, les mêmes pour toute ligne ; les
|
|
|
|
|
// rencontres répétées imposées dépendent du plan, et chaque ligne les lit
|
|
|
|
|
// dans ses mesures, à part des choisies.
|
[ADD] home: retained plan's collisions and redundancy gap per event
The event list showed no outcome, so comparing events meant opening each.
Each line now shows, for the retained plan only, the cumulated collisions
(pair and tour) and the redundancy gap |target - sum of r(p)|, with an
explanation tooltip; an event without a measurable retained plan shows a
dash. The target is set per event in Propositions, 1000 by default: an
optional settings field, absent in every existing file and read as 1000,
written through one undoable command refused in reading mode. Listing
stays read-only. Checked: 2909 node, 604 browser, 62 long tests.
--- FR ---
[ADD] accueil : collisions et Diff de redondance du retenu par événement
La liste des événements ne montrait aucun résultat : comparer obligeait à
ouvrir chacun. Chaque ligne montre, pour le retenu seul, les collisions
cumulées (paire et tour) et la Diff somme d'appartenance, |cible - somme
de r(p)|, avec une infobulle ; sans retenu mesurable, un tiret. La cible
se règle par événement dans Propositions, 1000 par défaut : champ
facultatif des réglages, absent de tout fichier existant et lu 1000, écrit
par une commande qui se défait et se refuse en lecture. La liste reste en
lecture seule. Vérifié : 2909 node, 604 navigateur, 62 longues.
Assisted-by: Claude Opus 5.5
2026-10-08 05:35:48 -04:00
|
|
|
//
|
[REF] event screen: no frame names, list summaries trimmed to use
The event list shows only the retained plan's redundancy gap and the id
of the best proposal, yet its summaries still carried cumulative
collisions and redundancy totals. They now carry what the list reads.
The mode frame is gone from the screen, so its names go too: the mode
surface component, the mode colour tokens and the bar's mode label are
named for what they are. Values, pixels and captures are unchanged.
Checked: node 4039, navigateur 884 with the walkthrough, node-long 105.
--- FR ---
[REF] écran d'événement : sans noms de cadre, résumés de liste réduits
La liste des événements ne montre que l'écart de redondance du retenu et
l'identifiant de la meilleure proposition, mais ses résumés portaient
encore les collisions cumulées et les totaux de redondance. Ils portent
désormais ce que la liste lit. Le cadre de mode a quitté l'écran, ses noms
aussi : le composant de surface, les jetons de couleur du mode et le
libellé de mode de la barre portent le nom de ce qu'ils sont. Valeurs,
pixels et captures inchangés.
Vérifié : node 4039, navigateur 884 avec le parcours, node-long 105.
Assisted-by: Claude Opus 5.5
2026-10-11 06:56:17 -04:00
|
|
|
// resumeDuRetenu donne à la liste des événements la différence à la cible
|
|
|
|
|
// du retenu, lue dans la même mesure que sa ligne du tableau, sans le
|
|
|
|
|
// diagnostic ni les plafonds : la liste en résume chaque événement du
|
|
|
|
|
// dossier. premiereDuClassement est la seule définition de la proposition
|
|
|
|
|
// au rang 1 : la section de la génération la lit dans sa table,
|
|
|
|
|
// resumeDuMeilleur en donne l'identifiant à la liste, sur la même table
|
|
|
|
|
// d'évaluation, diagnostic compris — le premier critère du classement lit
|
|
|
|
|
// le plafond a priori.
|
[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
|
|
|
import { classer } from '../moteur/classement.js';
|
|
|
|
|
import { indexerPlan, normaliser } from '../moteur/configuration.js';
|
|
|
|
|
import { diagnostiquer } from '../moteur/diagnostic.js';
|
|
|
|
|
import { mesurer } from '../moteur/indicateurs.js';
|
|
|
|
|
import { ecartsAuPlafondAPriori, minimumAtteint, troisChiffres } from '../moteur/manque.js';
|
|
|
|
|
import { plafondsRealises } from '../moteur/plafond.js';
|
|
|
|
|
import { verifierIndicateurs, verifierInvariants } from '../moteur/verification.js';
|
[ADD] home: retained plan's collisions and redundancy gap per event
The event list showed no outcome, so comparing events meant opening each.
Each line now shows, for the retained plan only, the cumulated collisions
(pair and tour) and the redundancy gap |target - sum of r(p)|, with an
explanation tooltip; an event without a measurable retained plan shows a
dash. The target is set per event in Propositions, 1000 by default: an
optional settings field, absent in every existing file and read as 1000,
written through one undoable command refused in reading mode. Listing
stays read-only. Checked: 2909 node, 604 browser, 62 long tests.
--- FR ---
[ADD] accueil : collisions et Diff de redondance du retenu par événement
La liste des événements ne montrait aucun résultat : comparer obligeait à
ouvrir chacun. Chaque ligne montre, pour le retenu seul, les collisions
cumulées (paire et tour) et la Diff somme d'appartenance, |cible - somme
de r(p)|, avec une infobulle ; sans retenu mesurable, un tiret. La cible
se règle par événement dans Propositions, 1000 par défaut : champ
facultatif des réglages, absent de tout fichier existant et lu 1000, écrit
par une commande qui se défait et se refuse en lecture. La liste reste en
lecture seule. Vérifié : 2909 node, 604 navigateur, 62 longues.
Assisted-by: Claude Opus 5.5
2026-10-08 05:35:48 -04:00
|
|
|
import { ErreurConfiguration } from '../moteur/erreurs.js';
|
|
|
|
|
import { CIBLE_REDONDANCE_PAR_DEFAUT, cibleRedondance, configurationDepuisCharge } from '../stockage/document.js';
|
[IMP] proposal evaluation: cached per frozen charge, validated once
The Génération and Propositions tabs re-evaluated every proposal on each
visit, about 1 ms per proposal, with no bound on how many accumulate.
The evaluation table is now kept per frozen event charge, which every
write replaces, and both tabs share it. Each placement is validated once
instead of three times; the public derive and planDepuisFichier still
validate, and a guard keeps the unchecked variants to evaluer alone.
At 200 proposals: Génération 214 to 17 ms on revisit, Propositions 310
to 118 ms. Checked: results deep-equal; node 4019, browser 873.
--- FR ---
[IMP] évaluation des propositions : gardée par charge, validée une fois
Les onglets Génération et Propositions réévaluaient toutes les
propositions à chaque visite, environ 1 ms chacune, sans borne sur leur
nombre. La table d'évaluation se garde par charge figée, qu'une écriture
remplace, et les deux onglets la partagent. Chaque placement se valide
une fois au lieu de trois ; derive et planDepuisFichier publics valident
toujours, une garde réserve les variantes sans contrôle à evaluer.
À 200 propositions : Génération 214 → 17 ms au retour, Propositions
310 → 118 ms. Vérifié : résultats identiques ; node 4019, nav. 873.
Assisted-by: Claude Opus 5.5
2026-10-11 03:43:47 -04:00
|
|
|
import { derive, deriveSansRevalider, fautes, planDepuisFichier, planSansRevalider } from '../stockage/placements.js';
|
[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] home: retained plan's collisions and redundancy gap per event
The event list showed no outcome, so comparing events meant opening each.
Each line now shows, for the retained plan only, the cumulated collisions
(pair and tour) and the redundancy gap |target - sum of r(p)|, with an
explanation tooltip; an event without a measurable retained plan shows a
dash. The target is set per event in Propositions, 1000 by default: an
optional settings field, absent in every existing file and read as 1000,
written through one undoable command refused in reading mode. Listing
stays read-only. Checked: 2909 node, 604 browser, 62 long tests.
--- FR ---
[ADD] accueil : collisions et Diff de redondance du retenu par événement
La liste des événements ne montrait aucun résultat : comparer obligeait à
ouvrir chacun. Chaque ligne montre, pour le retenu seul, les collisions
cumulées (paire et tour) et la Diff somme d'appartenance, |cible - somme
de r(p)|, avec une infobulle ; sans retenu mesurable, un tiret. La cible
se règle par événement dans Propositions, 1000 par défaut : champ
facultatif des réglages, absent de tout fichier existant et lu 1000, écrit
par une commande qui se défait et se refuse en lecture. La liste reste en
lecture seule. Vérifié : 2909 node, 604 navigateur, 62 longues.
Assisted-by: Claude Opus 5.5
2026-10-08 05:35:48 -04:00
|
|
|
export { CIBLE_REDONDANCE_PAR_DEFAUT, cibleRedondance };
|
|
|
|
|
|
[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
|
|
|
/**
|
|
|
|
|
* @typedef {Object} LigneEvaluation
|
|
|
|
|
* @property {number} id celui de la proposition ; retenu.proposition pour le retenu
|
|
|
|
|
* @property {'comparable'|'derive'|'fautif'} statut
|
|
|
|
|
* @property {object[]} raisons fautif : ses fautes ; derive : ses raisons ; [] sinon
|
|
|
|
|
* @property {object[]} violations comparable : les réservations non honorées
|
|
|
|
|
* (verifierInvariants, RESERVATION) ; [] sinon
|
|
|
|
|
* @property {object|null} mesures mesurer, telles quelles
|
|
|
|
|
* @property {number[]|null} plafondsRealises
|
|
|
|
|
* @property {object|null} troisChiffres
|
|
|
|
|
* @property {number|null} ecartAuPlafondAPrioriMax le plus grand de
|
|
|
|
|
* ecartsAuPlafondAPriori ; null quand l'a priori est inconnu ou la
|
|
|
|
|
* population vide
|
|
|
|
|
* @property {boolean|null} minimumAtteint
|
|
|
|
|
* @property {object[]} refusDessin verifierIndicateurs, chaque violation
|
|
|
|
|
* complétée de participant, l'identifiant de son index ; []
|
|
|
|
|
*
|
|
|
|
|
* @typedef {Object} TableEvaluation
|
|
|
|
|
* @property {number[]} population identifiants non exclus, croissants
|
|
|
|
|
* @property {LigneEvaluation[]} propositions comparables dans l'ordre du
|
|
|
|
|
* classement, puis les autres par identifiant
|
|
|
|
|
* @property {LigneEvaluation|null} retenu
|
|
|
|
|
* @property {{ordre: number[], criteresAppliques: string[], critereSaute: string|null}} classement
|
|
|
|
|
* classer, tel quel, sur les comparables
|
|
|
|
|
* @property {{retours: number, ancrages: number}} imposes
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// Le plus grand élément d'une liste ; null pour une liste vide ou absente.
|
|
|
|
|
function plusGrand(valeurs) {
|
|
|
|
|
if (valeurs === null || valeurs.length === 0) return null;
|
|
|
|
|
let plus = valeurs[0];
|
|
|
|
|
for (const valeur of valeurs) if (valeur > plus) plus = valeur;
|
|
|
|
|
return plus;
|
|
|
|
|
}
|
|
|
|
|
|
[ADD] home: retained plan's collisions and redundancy gap per event
The event list showed no outcome, so comparing events meant opening each.
Each line now shows, for the retained plan only, the cumulated collisions
(pair and tour) and the redundancy gap |target - sum of r(p)|, with an
explanation tooltip; an event without a measurable retained plan shows a
dash. The target is set per event in Propositions, 1000 by default: an
optional settings field, absent in every existing file and read as 1000,
written through one undoable command refused in reading mode. Listing
stays read-only. Checked: 2909 node, 604 browser, 62 long tests.
--- FR ---
[ADD] accueil : collisions et Diff de redondance du retenu par événement
La liste des événements ne montrait aucun résultat : comparer obligeait à
ouvrir chacun. Chaque ligne montre, pour le retenu seul, les collisions
cumulées (paire et tour) et la Diff somme d'appartenance, |cible - somme
de r(p)|, avec une infobulle ; sans retenu mesurable, un tiret. La cible
se règle par événement dans Propositions, 1000 par défaut : champ
facultatif des réglages, absent de tout fichier existant et lu 1000, écrit
par une commande qui se défait et se refuse en lecture. La liste reste en
lecture seule. Vérifié : 2909 node, 604 navigateur, 62 longues.
Assisted-by: Claude Opus 5.5
2026-10-08 05:35:48 -04:00
|
|
|
// Vrai quand le placement se compare à la configuration courante : sans
|
|
|
|
|
// faute, puis sans dérive — derive lève sur une faute, et ne la reçoit
|
|
|
|
|
// jamais.
|
|
|
|
|
const seCompare = (placement, charge) => fautes(placement).length === 0 && derive(placement, charge).length === 0;
|
|
|
|
|
|
[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
|
|
|
// Une ligne qui ne se mesure pas.
|
|
|
|
|
const nonMesuree = (id, statut, raisons) => ({
|
|
|
|
|
id,
|
|
|
|
|
statut,
|
|
|
|
|
raisons,
|
|
|
|
|
violations: [],
|
|
|
|
|
mesures: null,
|
|
|
|
|
plafondsRealises: null,
|
|
|
|
|
troisChiffres: null,
|
|
|
|
|
ecartAuPlafondAPrioriMax: null,
|
|
|
|
|
minimumAtteint: null,
|
|
|
|
|
refusDessin: [],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* La table d'évaluation d'une charge (contrat de A6). Ne modifie pas la
|
[IMP] proposal evaluation: cached per frozen charge, validated once
The Génération and Propositions tabs re-evaluated every proposal on each
visit, about 1 ms per proposal, with no bound on how many accumulate.
The evaluation table is now kept per frozen event charge, which every
write replaces, and both tabs share it. Each placement is validated once
instead of three times; the public derive and planDepuisFichier still
validate, and a guard keeps the unchecked variants to evaluer alone.
At 200 proposals: Génération 214 to 17 ms on revisit, Propositions 310
to 118 ms. Checked: results deep-equal; node 4019, browser 873.
--- FR ---
[IMP] évaluation des propositions : gardée par charge, validée une fois
Les onglets Génération et Propositions réévaluaient toutes les
propositions à chaque visite, environ 1 ms chacune, sans borne sur leur
nombre. La table d'évaluation se garde par charge figée, qu'une écriture
remplace, et les deux onglets la partagent. Chaque placement se valide
une fois au lieu de trois ; derive et planDepuisFichier publics valident
toujours, une garde réserve les variantes sans contrôle à evaluer.
À 200 propositions : Génération 214 → 17 ms au retour, Propositions
310 → 118 ms. Vérifié : résultats identiques ; node 4019, nav. 873.
Assisted-by: Claude Opus 5.5
2026-10-11 03:43:47 -04:00
|
|
|
* charge. Chaque proposition et le retenu se valident une seule fois, par
|
|
|
|
|
* fautes : fautif, le placement s'arrête là ; sans faute, sa dérive et son
|
|
|
|
|
* plan se lisent sans seconde validation.
|
[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('../stockage/types.js').Charge} charge
|
|
|
|
|
* @param {{plafondsAPriori?: 'calcul'|null}} [options]
|
|
|
|
|
* 'calcul' : le plafond a priori par personne du diagnostic, une seule
|
|
|
|
|
* maximisation ; null : a priori inconnu (§ 17, point 4)
|
|
|
|
|
* @returns {TableEvaluation}
|
|
|
|
|
* @throws {ErreurConfiguration} la configuration de la charge ne se
|
|
|
|
|
* normalise pas : rien ne se mesure, et la génération refuse la même
|
|
|
|
|
* @throws {TypeError} une autre valeur de plafondsAPriori
|
|
|
|
|
*/
|
|
|
|
|
export function evaluer(charge, { plafondsAPriori = 'calcul' } = {}) {
|
|
|
|
|
if (plafondsAPriori !== 'calcul' && plafondsAPriori !== null) {
|
|
|
|
|
throw new TypeError(`evaluer : plafondsAPriori 'calcul' ou null attendu, reçu ${JSON.stringify(plafondsAPriori)}`);
|
|
|
|
|
}
|
|
|
|
|
const configuration = configurationDepuisCharge(charge);
|
|
|
|
|
const diagnostic = diagnostiquer(configuration);
|
|
|
|
|
const instance = normaliser(configuration);
|
|
|
|
|
const aPriori = plafondsAPriori === 'calcul' ? diagnostic.plafondAPriori.parPersonne : null;
|
|
|
|
|
|
|
|
|
|
// La ligne d'un placement, proposition ou retenu, sous l'identifiant id.
|
|
|
|
|
function ligneDe(placement, id) {
|
|
|
|
|
const sesFautes = fautes(placement);
|
|
|
|
|
if (sesFautes.length > 0) return nonMesuree(id, 'fautif', sesFautes);
|
[IMP] proposal evaluation: cached per frozen charge, validated once
The Génération and Propositions tabs re-evaluated every proposal on each
visit, about 1 ms per proposal, with no bound on how many accumulate.
The evaluation table is now kept per frozen event charge, which every
write replaces, and both tabs share it. Each placement is validated once
instead of three times; the public derive and planDepuisFichier still
validate, and a guard keeps the unchecked variants to evaluer alone.
At 200 proposals: Génération 214 to 17 ms on revisit, Propositions 310
to 118 ms. Checked: results deep-equal; node 4019, browser 873.
--- FR ---
[IMP] évaluation des propositions : gardée par charge, validée une fois
Les onglets Génération et Propositions réévaluaient toutes les
propositions à chaque visite, environ 1 ms chacune, sans borne sur leur
nombre. La table d'évaluation se garde par charge figée, qu'une écriture
remplace, et les deux onglets la partagent. Chaque placement se valide
une fois au lieu de trois ; derive et planDepuisFichier publics valident
toujours, une garde réserve les variantes sans contrôle à evaluer.
À 200 propositions : Génération 214 → 17 ms au retour, Propositions
310 → 118 ms. Vérifié : résultats identiques ; node 4019, nav. 873.
Assisted-by: Claude Opus 5.5
2026-10-11 03:43:47 -04:00
|
|
|
const raisons = deriveSansRevalider(placement, charge);
|
[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
|
|
|
if (raisons.length > 0) return nonMesuree(id, 'derive', raisons);
|
[IMP] proposal evaluation: cached per frozen charge, validated once
The Génération and Propositions tabs re-evaluated every proposal on each
visit, about 1 ms per proposal, with no bound on how many accumulate.
The evaluation table is now kept per frozen event charge, which every
write replaces, and both tabs share it. Each placement is validated once
instead of three times; the public derive and planDepuisFichier still
validate, and a guard keeps the unchecked variants to evaluer alone.
At 200 proposals: Génération 214 to 17 ms on revisit, Propositions 310
to 118 ms. Checked: results deep-equal; node 4019, browser 873.
--- FR ---
[IMP] évaluation des propositions : gardée par charge, validée une fois
Les onglets Génération et Propositions réévaluaient toutes les
propositions à chaque visite, environ 1 ms chacune, sans borne sur leur
nombre. La table d'évaluation se garde par charge figée, qu'une écriture
remplace, et les deux onglets la partagent. Chaque placement se valide
une fois au lieu de trois ; derive et planDepuisFichier publics valident
toujours, une garde réserve les variantes sans contrôle à evaluer.
À 200 propositions : Génération 214 → 17 ms au retour, Propositions
310 → 118 ms. Vérifié : résultats identiques ; node 4019, nav. 873.
Assisted-by: Claude Opus 5.5
2026-10-11 03:43:47 -04:00
|
|
|
const plan = planSansRevalider(placement);
|
[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 tableDe = indexerPlan(instance, plan);
|
|
|
|
|
const mesures = mesurer(instance, tableDe);
|
|
|
|
|
const realises = plafondsRealises(instance, tableDe);
|
|
|
|
|
return {
|
|
|
|
|
id,
|
|
|
|
|
statut: 'comparable',
|
|
|
|
|
raisons: [],
|
|
|
|
|
violations: verifierInvariants(instance, plan, { reserveAutorisee: true }).filter(({ code }) => code === 'RESERVATION'),
|
|
|
|
|
mesures,
|
|
|
|
|
plafondsRealises: realises,
|
|
|
|
|
troisChiffres: troisChiffres(instance, mesures, aPriori, realises),
|
|
|
|
|
ecartAuPlafondAPrioriMax: plusGrand(ecartsAuPlafondAPriori(mesures, aPriori)),
|
|
|
|
|
minimumAtteint: minimumAtteint(mesures, aPriori),
|
|
|
|
|
refusDessin: verifierIndicateurs(mesures, aPriori, realises).map((violation) => ({
|
|
|
|
|
...violation,
|
|
|
|
|
participant: instance.ids[violation.index],
|
|
|
|
|
})),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const lignes = charge.propositions.map((proposition) => ligneDe(proposition, proposition.id));
|
|
|
|
|
const comparables = lignes.filter(({ statut }) => statut === 'comparable');
|
|
|
|
|
const classement = classer(comparables.map(({ id, mesures }) => ({ id, mesures, plafondsAPriori: aPriori })));
|
|
|
|
|
const rangDe = new Map(classement.ordre.map((id, rang) => [id, rang]));
|
|
|
|
|
const autres = lignes.filter(({ statut }) => statut !== 'comparable').sort((a, b) => a.id - b.id);
|
|
|
|
|
return {
|
|
|
|
|
population: [...instance.ids],
|
|
|
|
|
propositions: [...comparables.sort((a, b) => rangDe.get(a.id) - rangDe.get(b.id)), ...autres],
|
|
|
|
|
retenu: charge.retenu === null ? null : ligneDe(charge.retenu, charge.retenu.proposition),
|
|
|
|
|
classement,
|
|
|
|
|
imposes: { retours: diagnostic.retoursImposes, ancrages: diagnostic.ancragesImposantRetours },
|
|
|
|
|
};
|
|
|
|
|
}
|
[ADD] home: retained plan's collisions and redundancy gap per event
The event list showed no outcome, so comparing events meant opening each.
Each line now shows, for the retained plan only, the cumulated collisions
(pair and tour) and the redundancy gap |target - sum of r(p)|, with an
explanation tooltip; an event without a measurable retained plan shows a
dash. The target is set per event in Propositions, 1000 by default: an
optional settings field, absent in every existing file and read as 1000,
written through one undoable command refused in reading mode. Listing
stays read-only. Checked: 2909 node, 604 browser, 62 long tests.
--- FR ---
[ADD] accueil : collisions et Diff de redondance du retenu par événement
La liste des événements ne montrait aucun résultat : comparer obligeait à
ouvrir chacun. Chaque ligne montre, pour le retenu seul, les collisions
cumulées (paire et tour) et la Diff somme d'appartenance, |cible - somme
de r(p)|, avec une infobulle ; sans retenu mesurable, un tiret. La cible
se règle par événement dans Propositions, 1000 par défaut : champ
facultatif des réglages, absent de tout fichier existant et lu 1000, écrit
par une commande qui se défait et se refuse en lecture. La liste reste en
lecture seule. Vérifié : 2909 node, 604 navigateur, 62 longues.
Assisted-by: Claude Opus 5.5
2026-10-08 05:35:48 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Le résumé du retenu que montre la liste des événements (§ 5.4, § 8.1,
|
[REF] event screen: no frame names, list summaries trimmed to use
The event list shows only the retained plan's redundancy gap and the id
of the best proposal, yet its summaries still carried cumulative
collisions and redundancy totals. They now carry what the list reads.
The mode frame is gone from the screen, so its names go too: the mode
surface component, the mode colour tokens and the bar's mode label are
named for what they are. Values, pixels and captures are unchanged.
Checked: node 4039, navigateur 884 with the walkthrough, node-long 105.
--- FR ---
[REF] écran d'événement : sans noms de cadre, résumés de liste réduits
La liste des événements ne montre que l'écart de redondance du retenu et
l'identifiant de la meilleure proposition, mais ses résumés portaient
encore les collisions cumulées et les totaux de redondance. Ils portent
désormais ce que la liste lit. Le cadre de mode a quitté l'écran, ses noms
aussi : le composant de surface, les jetons de couleur du mode et le
libellé de mode de la barre portent le nom de ce qu'ils sont. Valeurs,
pixels et captures inchangés.
Vérifié : node 4039, navigateur 884 avec le parcours, node-long 105.
Assisted-by: Claude Opus 5.5
2026-10-11 06:56:17 -04:00
|
|
|
* § 8.9) : diffRedondance, la valeur absolue de la cible de l'événement
|
|
|
|
|
* (cibleRedondance) moins la somme de redondance Σ r(p) du retenu, celle de
|
|
|
|
|
* mesurer, que la ligne du retenu d'evaluer porte aussi. null sans retenu,
|
|
|
|
|
* pour un retenu fautif ou en dérive, et quand la configuration ne se
|
|
|
|
|
* normalise pas : rien ne s'y mesure, et la liste écrit « — ». Ne modifie
|
|
|
|
|
* pas la charge.
|
[ADD] home: retained plan's collisions and redundancy gap per event
The event list showed no outcome, so comparing events meant opening each.
Each line now shows, for the retained plan only, the cumulated collisions
(pair and tour) and the redundancy gap |target - sum of r(p)|, with an
explanation tooltip; an event without a measurable retained plan shows a
dash. The target is set per event in Propositions, 1000 by default: an
optional settings field, absent in every existing file and read as 1000,
written through one undoable command refused in reading mode. Listing
stays read-only. Checked: 2909 node, 604 browser, 62 long tests.
--- FR ---
[ADD] accueil : collisions et Diff de redondance du retenu par événement
La liste des événements ne montrait aucun résultat : comparer obligeait à
ouvrir chacun. Chaque ligne montre, pour le retenu seul, les collisions
cumulées (paire et tour) et la Diff somme d'appartenance, |cible - somme
de r(p)|, avec une infobulle ; sans retenu mesurable, un tiret. La cible
se règle par événement dans Propositions, 1000 par défaut : champ
facultatif des réglages, absent de tout fichier existant et lu 1000, écrit
par une commande qui se défait et se refuse en lecture. La liste reste en
lecture seule. Vérifié : 2909 node, 604 navigateur, 62 longues.
Assisted-by: Claude Opus 5.5
2026-10-08 05:35:48 -04:00
|
|
|
*
|
|
|
|
|
* @param {import('../stockage/types.js').Charge} charge
|
[REF] event screen: no frame names, list summaries trimmed to use
The event list shows only the retained plan's redundancy gap and the id
of the best proposal, yet its summaries still carried cumulative
collisions and redundancy totals. They now carry what the list reads.
The mode frame is gone from the screen, so its names go too: the mode
surface component, the mode colour tokens and the bar's mode label are
named for what they are. Values, pixels and captures are unchanged.
Checked: node 4039, navigateur 884 with the walkthrough, node-long 105.
--- FR ---
[REF] écran d'événement : sans noms de cadre, résumés de liste réduits
La liste des événements ne montre que l'écart de redondance du retenu et
l'identifiant de la meilleure proposition, mais ses résumés portaient
encore les collisions cumulées et les totaux de redondance. Ils portent
désormais ce que la liste lit. Le cadre de mode a quitté l'écran, ses noms
aussi : le composant de surface, les jetons de couleur du mode et le
libellé de mode de la barre portent le nom de ce qu'ils sont. Valeurs,
pixels et captures inchangés.
Vérifié : node 4039, navigateur 884 avec le parcours, node-long 105.
Assisted-by: Claude Opus 5.5
2026-10-11 06:56:17 -04:00
|
|
|
* @returns {{diffRedondance: number}|null}
|
[ADD] home: retained plan's collisions and redundancy gap per event
The event list showed no outcome, so comparing events meant opening each.
Each line now shows, for the retained plan only, the cumulated collisions
(pair and tour) and the redundancy gap |target - sum of r(p)|, with an
explanation tooltip; an event without a measurable retained plan shows a
dash. The target is set per event in Propositions, 1000 by default: an
optional settings field, absent in every existing file and read as 1000,
written through one undoable command refused in reading mode. Listing
stays read-only. Checked: 2909 node, 604 browser, 62 long tests.
--- FR ---
[ADD] accueil : collisions et Diff de redondance du retenu par événement
La liste des événements ne montrait aucun résultat : comparer obligeait à
ouvrir chacun. Chaque ligne montre, pour le retenu seul, les collisions
cumulées (paire et tour) et la Diff somme d'appartenance, |cible - somme
de r(p)|, avec une infobulle ; sans retenu mesurable, un tiret. La cible
se règle par événement dans Propositions, 1000 par défaut : champ
facultatif des réglages, absent de tout fichier existant et lu 1000, écrit
par une commande qui se défait et se refuse en lecture. La liste reste en
lecture seule. Vérifié : 2909 node, 604 navigateur, 62 longues.
Assisted-by: Claude Opus 5.5
2026-10-08 05:35:48 -04:00
|
|
|
*/
|
|
|
|
|
export function resumeDuRetenu(charge) {
|
|
|
|
|
const { retenu } = charge;
|
|
|
|
|
if (retenu === null || !seCompare(retenu, charge)) return null;
|
|
|
|
|
let instance;
|
|
|
|
|
try {
|
|
|
|
|
instance = normaliser(configurationDepuisCharge(charge));
|
|
|
|
|
} catch (erreur) {
|
|
|
|
|
if (erreur instanceof ErreurConfiguration) return null;
|
|
|
|
|
throw erreur;
|
|
|
|
|
}
|
[REF] event screen: no frame names, list summaries trimmed to use
The event list shows only the retained plan's redundancy gap and the id
of the best proposal, yet its summaries still carried cumulative
collisions and redundancy totals. They now carry what the list reads.
The mode frame is gone from the screen, so its names go too: the mode
surface component, the mode colour tokens and the bar's mode label are
named for what they are. Values, pixels and captures are unchanged.
Checked: node 4039, navigateur 884 with the walkthrough, node-long 105.
--- FR ---
[REF] écran d'événement : sans noms de cadre, résumés de liste réduits
La liste des événements ne montre que l'écart de redondance du retenu et
l'identifiant de la meilleure proposition, mais ses résumés portaient
encore les collisions cumulées et les totaux de redondance. Ils portent
désormais ce que la liste lit. Le cadre de mode a quitté l'écran, ses noms
aussi : le composant de surface, les jetons de couleur du mode et le
libellé de mode de la barre portent le nom de ce qu'ils sont. Valeurs,
pixels et captures inchangés.
Vérifié : node 4039, navigateur 884 avec le parcours, node-long 105.
Assisted-by: Claude Opus 5.5
2026-10-11 06:56:17 -04:00
|
|
|
const { totalRedondance } = mesurer(instance, indexerPlan(instance, planDepuisFichier(retenu)));
|
|
|
|
|
return { diffRedondance: Math.abs(cibleRedondance(charge) - totalRedondance) };
|
[ADD] home: retained plan's collisions and redundancy gap per event
The event list showed no outcome, so comparing events meant opening each.
Each line now shows, for the retained plan only, the cumulated collisions
(pair and tour) and the redundancy gap |target - sum of r(p)|, with an
explanation tooltip; an event without a measurable retained plan shows a
dash. The target is set per event in Propositions, 1000 by default: an
optional settings field, absent in every existing file and read as 1000,
written through one undoable command refused in reading mode. Listing
stays read-only. Checked: 2909 node, 604 browser, 62 long tests.
--- FR ---
[ADD] accueil : collisions et Diff de redondance du retenu par événement
La liste des événements ne montrait aucun résultat : comparer obligeait à
ouvrir chacun. Chaque ligne montre, pour le retenu seul, les collisions
cumulées (paire et tour) et la Diff somme d'appartenance, |cible - somme
de r(p)|, avec une infobulle ; sans retenu mesurable, un tiret. La cible
se règle par événement dans Propositions, 1000 par défaut : champ
facultatif des réglages, absent de tout fichier existant et lu 1000, écrit
par une commande qui se défait et se refuse en lecture. La liste reste en
lecture seule. Vérifié : 2909 node, 604 navigateur, 62 longues.
Assisted-by: Claude Opus 5.5
2026-10-08 05:35:48 -04:00
|
|
|
}
|
[ADD] home: best ranked proposition on every event line
Each event line of the home lists now names its rank-1 proposition and
its cumulated collisions, whether or not a plan is retained, with the
same label and tooltip as the generation block. One application function
picks the rank-1 proposition for both places, so the list, the generation
block and the propositions table show the same proposition and number.
The list reads the examined charge, as opening the event does, so a file
with a repeated proposition identifier no longer hides the whole folder.
Checked: 2923 node, 609 browser, 62 long tests, from the index alone.
--- FR ---
[ADD] accueil : meilleure proposition classée sur chaque événement
Chaque ligne des listes de l'accueil nomme sa proposition de rang 1 et ses
collisions cumulées, retenu ou non, avec le même libellé et la même
infobulle que le bloc de la génération. Une seule fonction d'application
désigne le rang 1 aux deux endroits : la liste, le bloc et le tableau des
propositions montrent la même proposition et le même nombre. La liste lit
la charge examinée, comme l'ouverture : un fichier dont une proposition
répète un identifiant ne fait plus disparaître tout le dossier.
Vérifié : 2923 node, 609 navigateur, 62 longues, depuis l'index seul.
Assisted-by: Claude Opus 5.5
2026-10-08 06:06:21 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* La proposition au rang 1 du classement d'une table d'évaluation (§ 5.7) :
|
|
|
|
|
* la première de ses propositions quand elle se compare — les comparables
|
|
|
|
|
* ouvrent la liste, dans l'ordre du classement —, null quand aucune ne se
|
|
|
|
|
* classe.
|
|
|
|
|
*
|
|
|
|
|
* @param {TableEvaluation} table
|
|
|
|
|
* @returns {LigneEvaluation|null}
|
|
|
|
|
*/
|
|
|
|
|
export function premiereDuClassement(table) {
|
|
|
|
|
const [premiere] = table.propositions;
|
|
|
|
|
return premiere !== undefined && premiere.statut === 'comparable' ? premiere : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* La meilleure proposition du classement que montre la liste des
|
[REF] event screen: no frame names, list summaries trimmed to use
The event list shows only the retained plan's redundancy gap and the id
of the best proposal, yet its summaries still carried cumulative
collisions and redundancy totals. They now carry what the list reads.
The mode frame is gone from the screen, so its names go too: the mode
surface component, the mode colour tokens and the bar's mode label are
named for what they are. Values, pixels and captures are unchanged.
Checked: node 4039, navigateur 884 with the walkthrough, node-long 105.
--- FR ---
[REF] écran d'événement : sans noms de cadre, résumés de liste réduits
La liste des événements ne montre que l'écart de redondance du retenu et
l'identifiant de la meilleure proposition, mais ses résumés portaient
encore les collisions cumulées et les totaux de redondance. Ils portent
désormais ce que la liste lit. Le cadre de mode a quitté l'écran, ses noms
aussi : le composant de surface, les jetons de couleur du mode et le
libellé de mode de la barre portent le nom de ce qu'ils sont. Valeurs,
pixels et captures inchangés.
Vérifié : node 4039, navigateur 884 avec le parcours, node-long 105.
Assisted-by: Claude Opus 5.5
2026-10-11 06:56:17 -04:00
|
|
|
* événements (§ 5.4, § 5.7, § 8.1) : id, l'identifiant de la proposition au
|
|
|
|
|
* rang 1 (premiereDuClassement). null sans proposition, quand aucune ne se
|
|
|
|
|
* compare — toutes fautives ou en dérive —, et quand la configuration ne se
|
|
|
|
|
* normalise pas : la liste écrit alors « — ». Le retenu n'y entre pas. Ne
|
|
|
|
|
* modifie pas la charge.
|
[ADD] home: best ranked proposition on every event line
Each event line of the home lists now names its rank-1 proposition and
its cumulated collisions, whether or not a plan is retained, with the
same label and tooltip as the generation block. One application function
picks the rank-1 proposition for both places, so the list, the generation
block and the propositions table show the same proposition and number.
The list reads the examined charge, as opening the event does, so a file
with a repeated proposition identifier no longer hides the whole folder.
Checked: 2923 node, 609 browser, 62 long tests, from the index alone.
--- FR ---
[ADD] accueil : meilleure proposition classée sur chaque événement
Chaque ligne des listes de l'accueil nomme sa proposition de rang 1 et ses
collisions cumulées, retenu ou non, avec le même libellé et la même
infobulle que le bloc de la génération. Une seule fonction d'application
désigne le rang 1 aux deux endroits : la liste, le bloc et le tableau des
propositions montrent la même proposition et le même nombre. La liste lit
la charge examinée, comme l'ouverture : un fichier dont une proposition
répète un identifiant ne fait plus disparaître tout le dossier.
Vérifié : 2923 node, 609 navigateur, 62 longues, depuis l'index seul.
Assisted-by: Claude Opus 5.5
2026-10-08 06:06:21 -04:00
|
|
|
*
|
|
|
|
|
* @param {import('../stockage/types.js').Charge} charge
|
[REF] event screen: no frame names, list summaries trimmed to use
The event list shows only the retained plan's redundancy gap and the id
of the best proposal, yet its summaries still carried cumulative
collisions and redundancy totals. They now carry what the list reads.
The mode frame is gone from the screen, so its names go too: the mode
surface component, the mode colour tokens and the bar's mode label are
named for what they are. Values, pixels and captures are unchanged.
Checked: node 4039, navigateur 884 with the walkthrough, node-long 105.
--- FR ---
[REF] écran d'événement : sans noms de cadre, résumés de liste réduits
La liste des événements ne montre que l'écart de redondance du retenu et
l'identifiant de la meilleure proposition, mais ses résumés portaient
encore les collisions cumulées et les totaux de redondance. Ils portent
désormais ce que la liste lit. Le cadre de mode a quitté l'écran, ses noms
aussi : le composant de surface, les jetons de couleur du mode et le
libellé de mode de la barre portent le nom de ce qu'ils sont. Valeurs,
pixels et captures inchangés.
Vérifié : node 4039, navigateur 884 avec le parcours, node-long 105.
Assisted-by: Claude Opus 5.5
2026-10-11 06:56:17 -04:00
|
|
|
* @returns {{id: number}|null}
|
[ADD] home: best ranked proposition on every event line
Each event line of the home lists now names its rank-1 proposition and
its cumulated collisions, whether or not a plan is retained, with the
same label and tooltip as the generation block. One application function
picks the rank-1 proposition for both places, so the list, the generation
block and the propositions table show the same proposition and number.
The list reads the examined charge, as opening the event does, so a file
with a repeated proposition identifier no longer hides the whole folder.
Checked: 2923 node, 609 browser, 62 long tests, from the index alone.
--- FR ---
[ADD] accueil : meilleure proposition classée sur chaque événement
Chaque ligne des listes de l'accueil nomme sa proposition de rang 1 et ses
collisions cumulées, retenu ou non, avec le même libellé et la même
infobulle que le bloc de la génération. Une seule fonction d'application
désigne le rang 1 aux deux endroits : la liste, le bloc et le tableau des
propositions montrent la même proposition et le même nombre. La liste lit
la charge examinée, comme l'ouverture : un fichier dont une proposition
répète un identifiant ne fait plus disparaître tout le dossier.
Vérifié : 2923 node, 609 navigateur, 62 longues, depuis l'index seul.
Assisted-by: Claude Opus 5.5
2026-10-08 06:06:21 -04:00
|
|
|
*/
|
|
|
|
|
export function resumeDuMeilleur(charge) {
|
|
|
|
|
if (charge.propositions.length === 0) return null;
|
|
|
|
|
let table;
|
|
|
|
|
try {
|
|
|
|
|
table = evaluer(charge);
|
|
|
|
|
} catch (erreur) {
|
|
|
|
|
if (erreur instanceof ErreurConfiguration) return null;
|
|
|
|
|
throw erreur;
|
|
|
|
|
}
|
|
|
|
|
const premiere = premiereDuClassement(table);
|
[REF] event screen: no frame names, list summaries trimmed to use
The event list shows only the retained plan's redundancy gap and the id
of the best proposal, yet its summaries still carried cumulative
collisions and redundancy totals. They now carry what the list reads.
The mode frame is gone from the screen, so its names go too: the mode
surface component, the mode colour tokens and the bar's mode label are
named for what they are. Values, pixels and captures are unchanged.
Checked: node 4039, navigateur 884 with the walkthrough, node-long 105.
--- FR ---
[REF] écran d'événement : sans noms de cadre, résumés de liste réduits
La liste des événements ne montre que l'écart de redondance du retenu et
l'identifiant de la meilleure proposition, mais ses résumés portaient
encore les collisions cumulées et les totaux de redondance. Ils portent
désormais ce que la liste lit. Le cadre de mode a quitté l'écran, ses noms
aussi : le composant de surface, les jetons de couleur du mode et le
libellé de mode de la barre portent le nom de ce qu'ils sont. Valeurs,
pixels et captures inchangés.
Vérifié : node 4039, navigateur 884 avec le parcours, node-long 105.
Assisted-by: Claude Opus 5.5
2026-10-11 06:56:17 -04:00
|
|
|
return premiere === null ? null : { id: premiere.id };
|
[ADD] home: best ranked proposition on every event line
Each event line of the home lists now names its rank-1 proposition and
its cumulated collisions, whether or not a plan is retained, with the
same label and tooltip as the generation block. One application function
picks the rank-1 proposition for both places, so the list, the generation
block and the propositions table show the same proposition and number.
The list reads the examined charge, as opening the event does, so a file
with a repeated proposition identifier no longer hides the whole folder.
Checked: 2923 node, 609 browser, 62 long tests, from the index alone.
--- FR ---
[ADD] accueil : meilleure proposition classée sur chaque événement
Chaque ligne des listes de l'accueil nomme sa proposition de rang 1 et ses
collisions cumulées, retenu ou non, avec le même libellé et la même
infobulle que le bloc de la génération. Une seule fonction d'application
désigne le rang 1 aux deux endroits : la liste, le bloc et le tableau des
propositions montrent la même proposition et le même nombre. La liste lit
la charge examinée, comme l'ouverture : un fichier dont une proposition
répète un identifiant ne fait plus disparaître tout le dossier.
Vérifié : 2923 node, 609 navigateur, 62 longues, depuis l'index seul.
Assisted-by: Claude Opus 5.5
2026-10-08 06:06:21 -04:00
|
|
|
}
|