[ADD] application: clock, translation, formatting, displayed name
The screens need one clock, one translation mechanism and one way to
format and name, or each component grows its own. horloge.js is the only
code that reads time and arms timers, injected so tests drive it.
traduction.js keys texts by domain, in two families of tables, raises on a
missing key and never shows a raw key; libelles/ splits the label table by
domain. format.js formats numbers and dates in French, and personnes.js
composes the displayed name the frozen labels use. Nothing persists
between sessions.
Checked: 1773 node and 43 browser tests.
--- FR ---
[ADD] application : horloge, traduction, mise en forme, nom affiché
Les écrans exigent une horloge, un mécanisme de traduction et une façon de
mettre en forme et de nommer, sans quoi chaque composant ferait les siens.
horloge.js est le seul code qui lit l'heure et arme des minuteries, injecté
pour que les épreuves le pilotent. traduction.js range les textes par
domaine, en deux familles de tables, lève sur une clé absente et ne montre
jamais une clé brute ; libelles/ découpe la table des libellés par domaine.
format.js met en forme nombres et dates en français, et personnes.js
compose le nom affiché qu'emploient les libellés figés. Rien ne persiste
d'une séance à l'autre.
Vérifié : 1773 node et 43 navigateur.
Assisted-by: Claude Opus 5.5
2026-10-07 02:33:39 -04:00
|
|
|
// © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
|
|
|
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
|
|
|
|
|
|
|
|
|
// Les textes des commandes de la génération et des propositions (§ 5.7,
|
[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
|
|
|
// § 14.6) : refus et libellés figés, puis les refus du contrôleur de
|
|
|
|
|
// génération et de la saisie de ses réglages (§ 5.9, § 5.10, § 15.4). Cette
|
|
|
|
|
// table ne porte que des codes. Un nombre et une durée se mettent en forme
|
|
|
|
|
// par creerFormat, sur la composition que la traduction passe à l'entrée.
|
|
|
|
|
import { creerFormat } from '../format.js';
|
|
|
|
|
import { cite, compte, phraseDeRaison } from './aides.js';
|
|
|
|
|
|
|
|
|
|
// Le nom de chaque réglage de génération, celui que la saisie affiche.
|
|
|
|
|
const NOMS_DES_REGLAGES = new Map([
|
|
|
|
|
['graine', 'Graine'],
|
|
|
|
|
['nombre', 'Propositions par génération'],
|
|
|
|
|
['arret', 'Mouvements par proposition'],
|
|
|
|
|
['historique', "Historique d'acceptation"],
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// L'estimation d'une génération longue, en mots : l'ordre de grandeur et la
|
|
|
|
|
// mesure dont il vient, ou le seuil d'une génération sans mesure.
|
|
|
|
|
function phraseEstimation(estimation, texte) {
|
|
|
|
|
if (estimation.inconnue === true) {
|
|
|
|
|
return (
|
|
|
|
|
"Aucune durée n'est encore mesurée sur ce poste dans cette séance, et ce réglage demande plus de " +
|
|
|
|
|
'dix fois le réglage par défaut'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
const format = creerFormat(texte);
|
|
|
|
|
const { mesure } = estimation;
|
|
|
|
|
const plafond = estimation.auDelaDuPlafond ? ", au-delà du plafond d'usage de trente minutes" : '';
|
|
|
|
|
return (
|
|
|
|
|
`Ce réglage prendrait ${format.ordreDeGrandeur(estimation.secondes)}${plafond}, d'après le dernier calcul, ` +
|
|
|
|
|
`${format.duree(mesure.dureeMs)} pour ${format.nombre(mesure.mouvements)} mouvements ` +
|
|
|
|
|
`sur ${compte(mesure.participants, 'participant', 'participants')}`
|
|
|
|
|
);
|
|
|
|
|
}
|
[ADD] application: clock, translation, formatting, displayed name
The screens need one clock, one translation mechanism and one way to
format and name, or each component grows its own. horloge.js is the only
code that reads time and arms timers, injected so tests drive it.
traduction.js keys texts by domain, in two families of tables, raises on a
missing key and never shows a raw key; libelles/ splits the label table by
domain. format.js formats numbers and dates in French, and personnes.js
composes the displayed name the frozen labels use. Nothing persists
between sessions.
Checked: 1773 node and 43 browser tests.
--- FR ---
[ADD] application : horloge, traduction, mise en forme, nom affiché
Les écrans exigent une horloge, un mécanisme de traduction et une façon de
mettre en forme et de nommer, sans quoi chaque composant ferait les siens.
horloge.js est le seul code qui lit l'heure et arme des minuteries, injecté
pour que les épreuves le pilotent. traduction.js range les textes par
domaine, en deux familles de tables, lève sur une clé absente et ne montre
jamais une clé brute ; libelles/ découpe la table des libellés par domaine.
format.js met en forme nombres et dates en français, et personnes.js
compose le nom affiché qu'emploient les libellés figés. Rien ne persiste
d'une séance à l'autre.
Vérifié : 1773 node et 43 navigateur.
Assisted-by: Claude Opus 5.5
2026-10-07 02:33:39 -04:00
|
|
|
|
|
|
|
|
export const TABLE = new Map([
|
|
|
|
|
// --- Les refus des propositions (§ 5.7) ------------------------------------
|
|
|
|
|
['PROPOSITION_INCONNUE', ({ id }) => `La proposition n° ${id} n'est pas dans cet événement.`],
|
|
|
|
|
|
|
|
|
|
// --- Les libellés figés du journal (§ 8.2, § 8.3) --------------------------
|
|
|
|
|
[
|
|
|
|
|
'ENTREE_ENREGISTRER_GENERATION',
|
|
|
|
|
({ n, premier, dernier }) =>
|
|
|
|
|
`Généré ${compte(n, 'proposition', 'propositions')} ` +
|
|
|
|
|
`(n° ${premier === dernier ? premier : `${premier} à ${dernier}`})`,
|
|
|
|
|
],
|
|
|
|
|
['ENTREE_RETENIR_PROPOSITION', ({ id }) => `Retenu la proposition n° ${id}`],
|
|
|
|
|
[
|
|
|
|
|
'ENTREE_EFFACER_PROPOSITIONS',
|
|
|
|
|
({ n, gardee }) =>
|
|
|
|
|
`Effacé ${compte(n, 'proposition', 'propositions')}` +
|
|
|
|
|
`${gardee === null || gardee === undefined ? '' : `, gardé la retenue (n° ${gardee})`}`,
|
|
|
|
|
],
|
[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 de génération (§ 5.9, § 5.10, § 15.4) -------------------
|
|
|
|
|
['GENERATION_EN_COURS', () => "Une génération est déjà en cours : l'annuler, ou attendre qu'elle s'achève."],
|
|
|
|
|
[
|
|
|
|
|
'AUCUN_PARTICIPANT',
|
|
|
|
|
() => "Aucune personne à placer : la liste des participants est vide, ou chacun en est exclu.",
|
|
|
|
|
],
|
|
|
|
|
['AUCUNE_TABLE', () => "Aucune table : la génération place les personnes autour des tables de l'événement."],
|
[FIX] iteration 3 review: seat targets, gestures, warnings, settings
The wheel no longer zooms during a gesture, so a drop lands under the
ghost. A seat is a target the size of its pitch. A floor drop refuses to
remove an every-tour reservation. A seat reservation the retained plan
does not hold is flagged at the seat, with its swap as remedy. DERIVE names
the person; capacities have an upper bound; Generate waits for a pending
setting; a worker that fails to load shows a refusal; § 5.3 constraints
get their switches. Commands are not re-entrant and a double click does not
confirm. Checked: 2755 node, 550 browser tests, from the index alone.
--- FR ---
[FIX] revue de l'itération 3 : cibles, gestes, avertissements, réglages
La molette ne zoome plus pendant un geste : le dépôt tombe sous le fantôme.
Un siège est une cible de la taille de son pas. Un dépôt sur le sol refuse
de retirer une réservation de tous les tours. Une réservation à un siège
que le retenu ne tient pas est relevée au siège, l'échange en remède. La
dérive nomme la personne ; les capacités ont une borne ; Générer attend un
réglage en cours ; un travailleur qui ne se charge pas donne un refus ; le
§ 5.3 a ses bascules. Les commandes ne sont pas ré-entrantes et un double
clic ne confirme pas. Vérifié : 2755 node, 550 navigateur, index seul.
Assisted-by: Claude Opus 5.5
2026-10-07 17:50:35 -04:00
|
|
|
// Le travailleur de génération n'a pas démarré, ou s'est arrêté sans
|
|
|
|
|
// résultat : rien n'est enregistré, et aucun geste de la page ne le relance.
|
|
|
|
|
[
|
|
|
|
|
'TRAVAILLEUR_EN_ECHEC',
|
|
|
|
|
() =>
|
|
|
|
|
"Le calcul hors de la page n'a pas pu se faire : le navigateur n'a pas démarré le travailleur de génération, " +
|
|
|
|
|
"ou l'a arrêté sans résultat. Rien n'est enregistré ; relancer le logiciel le recharge.",
|
|
|
|
|
],
|
[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
|
|
|
[
|
|
|
|
|
'CONFIRMATION_REQUISE',
|
|
|
|
|
({ estimation }, texte) =>
|
|
|
|
|
`${phraseEstimation(estimation, texte)}. Confirmer « Générer » lance quand même la génération.`,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'REGLAGE_HORS_DOMAINE',
|
|
|
|
|
({ reglage }) =>
|
|
|
|
|
`Le réglage ${cite(NOMS_DES_REGLAGES.get(reglage) ?? String(reglage))} sort de son domaine : ` +
|
|
|
|
|
"la génération n'a pas eu lieu.",
|
|
|
|
|
],
|
|
|
|
|
// rang : la place du placement dans la suite des graines du lancement,
|
|
|
|
|
// jamais un numéro de proposition, puisque rien n'est enregistré ; chaque
|
|
|
|
|
// violation se dit par le texte de son code (libelles/moteur.js).
|
|
|
|
|
[
|
|
|
|
|
'GENERATION_INVARIANT_VIOLE',
|
|
|
|
|
({ rang, violations }, texte) =>
|
|
|
|
|
`Le placement que la génération a rendu au rang ${rang} de ce lancement enfreint ` +
|
|
|
|
|
`${compte(violations.length, 'règle', 'règles')} ; rien n'est enregistré. ` +
|
|
|
|
|
violations.map((violation) => phraseDeRaison(violation.code, violation, texte)).join(' '),
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
// --- La saisie des réglages (§ 5.7) -----------------------------------------
|
|
|
|
|
// max null : le domaine n'a pas de borne supérieure.
|
|
|
|
|
[
|
|
|
|
|
'HORS_DOMAINE',
|
|
|
|
|
({ min, max }, texte) => {
|
|
|
|
|
const { nombre } = creerFormat(texte);
|
|
|
|
|
return max === null || max === undefined
|
|
|
|
|
? `La valeur doit être d'au moins ${nombre(min)}.`
|
|
|
|
|
: `La valeur doit être comprise entre ${nombre(min)} et ${nombre(max)}.`;
|
|
|
|
|
},
|
|
|
|
|
],
|
[ADD] application: clock, translation, formatting, displayed name
The screens need one clock, one translation mechanism and one way to
format and name, or each component grows its own. horloge.js is the only
code that reads time and arms timers, injected so tests drive it.
traduction.js keys texts by domain, in two families of tables, raises on a
missing key and never shows a raw key; libelles/ splits the label table by
domain. format.js formats numbers and dates in French, and personnes.js
composes the displayed name the frozen labels use. Nothing persists
between sessions.
Checked: 1773 node and 43 browser tests.
--- FR ---
[ADD] application : horloge, traduction, mise en forme, nom affiché
Les écrans exigent une horloge, un mécanisme de traduction et une façon de
mettre en forme et de nommer, sans quoi chaque composant ferait les siens.
horloge.js est le seul code qui lit l'heure et arme des minuteries, injecté
pour que les épreuves le pilotent. traduction.js range les textes par
domaine, en deux familles de tables, lève sur une clé absente et ne montre
jamais une clé brute ; libelles/ découpe la table des libellés par domaine.
format.js met en forme nombres et dates en français, et personnes.js
compose le nom affiché qu'emploient les libellés figés. Rien ne persiste
d'une séance à l'autre.
Vérifié : 1773 node et 43 navigateur.
Assisted-by: Claude Opus 5.5
2026-10-07 02:33:39 -04:00
|
|
|
]);
|