[ADD] application: observable session, events facade, places and seats
The screens of iteration 3 need state they can subscribe to and commands
that keep the plan sound. The session follows the Svelte store contract,
unblocks a plan, cancels a gesture, keeps the framing, and orders the
warnings of a gesture. The facade lists events, settles the working folder
and runs copy, rename, import and delete. Places cover reservations, titles,
designation and the retained plan: each gesture reads seats as the display
shows them, reserved people keep their table, and a person removed frees
her chair while every other seat stays.
Checked: 1973 node, 127 browser, 60 node-long tests; coverage floors kept.
--- FR ---
[ADD] application : séance observable, façade des événements, places
Les écrans de l'itération 3 exigent un état auquel s'abonner et des
commandes qui gardent le plan sain. La séance suit le contrat des magasins
de Svelte, débloque un plan, annule un geste, garde le cadrage et ordonne
les avertissements d'un geste. La façade liste les événements, règle le
dossier de travail et mène copie, renommage, import et suppression. Les
places couvrent réservations, titres, désignation et plan retenu : chaque
geste lit les sièges comme l'écran les montre, une personne réservée garde
sa table, et une personne retirée libère sa chaise sans déplacer les autres.
Vérifié : 1973 node, 127 navigateur, 60 node-long ; seuils de couverture.
Assisted-by: Claude Opus 5.5
2026-10-07 04:14:24 -04:00
|
|
|
// © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
|
|
|
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
|
|
|
|
|
|
|
|
|
// Les avertissements qu'un geste fait naître (§ 5.9, § 9, § 14.12), calculés
|
|
|
|
|
// de la charge d'avant à celle d'après, et les violations du retenu que la
|
|
|
|
|
// séance montre tant que la charge les porte. Un avertissement n'empêche
|
|
|
|
|
// rien : il dit ce que le geste a changé, avec le nombre.
|
|
|
|
|
//
|
|
|
|
|
// Aucun calcul ne lève sur un placement. Les raisons de dérive se lisent sur
|
|
|
|
|
// examiner (S2), qui les rend pour tout placement cohérent, dérivé compris ;
|
|
|
|
|
// le retenu ne se juge contre l'instance par verifierInvariants que quand
|
|
|
|
|
// examiner ne lui trouve aucune faute, et que la configuration se normalise.
|
|
|
|
|
// Ni indexerPlan ni derive n'entrent ici : le premier lève sur un plan qui ne
|
|
|
|
|
// décrit plus la configuration, le second sur un placement fautif.
|
|
|
|
|
import { ErreurConfiguration } from '../moteur/erreurs.js';
|
[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
|
|
|
import { LIBRE, nombrePlacesManquantes, normaliser } from '../moteur/configuration.js';
|
[ADD] application: observable session, events facade, places and seats
The screens of iteration 3 need state they can subscribe to and commands
that keep the plan sound. The session follows the Svelte store contract,
unblocks a plan, cancels a gesture, keeps the framing, and orders the
warnings of a gesture. The facade lists events, settles the working folder
and runs copy, rename, import and delete. Places cover reservations, titles,
designation and the retained plan: each gesture reads seats as the display
shows them, reserved people keep their table, and a person removed frees
her chair while every other seat stays.
Checked: 1973 node, 127 browser, 60 node-long tests; coverage floors kept.
--- FR ---
[ADD] application : séance observable, façade des événements, places
Les écrans de l'itération 3 exigent un état auquel s'abonner et des
commandes qui gardent le plan sain. La séance suit le contrat des magasins
de Svelte, débloque un plan, annule un geste, garde le cadrage et ordonne
les avertissements d'un geste. La façade liste les événements, règle le
dossier de travail et mène copie, renommage, import et suppression. Les
places couvrent réservations, titres, désignation et plan retenu : chaque
geste lit les sièges comme l'écran les montre, une personne réservée garde
sa table, et une personne retirée libère sa chaise sans déplacer les autres.
Vérifié : 1973 node, 127 navigateur, 60 node-long ; seuils de couverture.
Assisted-by: Claude Opus 5.5
2026-10-07 04:14:24 -04:00
|
|
|
import { verifierInvariants } from '../moteur/verification.js';
|
[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
|
|
|
import { capacite, configurationDepuisCharge } from '../stockage/document.js';
|
[ADD] application: observable session, events facade, places and seats
The screens of iteration 3 need state they can subscribe to and commands
that keep the plan sound. The session follows the Svelte store contract,
unblocks a plan, cancels a gesture, keeps the framing, and orders the
warnings of a gesture. The facade lists events, settles the working folder
and runs copy, rename, import and delete. Places cover reservations, titles,
designation and the retained plan: each gesture reads seats as the display
shows them, reserved people keep their table, and a person removed frees
her chair while every other seat stays.
Checked: 1973 node, 127 browser, 60 node-long tests; coverage floors kept.
--- FR ---
[ADD] application : séance observable, façade des événements, places
Les écrans de l'itération 3 exigent un état auquel s'abonner et des
commandes qui gardent le plan sain. La séance suit le contrat des magasins
de Svelte, débloque un plan, annule un geste, garde le cadrage et ordonne
les avertissements d'un geste. La façade liste les événements, règle le
dossier de travail et mène copie, renommage, import et suppression. Les
places couvrent réservations, titres, désignation et plan retenu : chaque
geste lit les sièges comme l'écran les montre, une personne réservée garde
sa table, et une personne retirée libère sa chaise sans déplacer les autres.
Vérifié : 1973 node, 127 navigateur, 60 node-long ; seuils de couverture.
Assisted-by: Claude Opus 5.5
2026-10-07 04:14:24 -04:00
|
|
|
import { examiner, planDepuisFichier } from '../stockage/placements.js';
|
[FIX] plan: named warning, one places state, highlight, table spacing
The unheld-reservation warning names the person and the table number
instead of their identifiers. The places state is computed once per change
and handed to the side panels, not once per panel. A person can be
highlighted from their menu or from the grid, and the view bar names them.
A created table takes a cell a full pitch away from every table, its own
capacity included, so no name list runs over a neighbour's chairs. The
rendering guards fail on an empty walk and also check focus and selection.
Checked: 2692 node, 496 browser, 60 long tests, from the index alone.
--- FR ---
[FIX] plan : avertissement nommé, état des places unique, évidence, pas
L'avertissement de réservation non honorée nomme la personne et le numéro
de la table plutôt que leurs identifiants. L'état des places se calcule une
fois par changement et passe aux panneaux, non une fois par panneau. Une
personne se met en évidence par son menu ou depuis la grille, et la barre
de vue la nomme. Une table créée prend une case à un pas plein de chaque
table, sa capacité comprise : aucune liste ne court sur les chaises
voisines. Les gardes du rendu échouent sur un parcours vide et éprouvent
aussi le focus et la sélection. Vérifié : 2692 node, 496 navigateur, 60.
Assisted-by: Claude Opus 5.5
2026-10-07 15:05:01 -04:00
|
|
|
import { nomAffiche } from './personnes.js';
|
[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
|
|
|
import { couvre, placesTenues, presents, reservationsActives } from './places.js';
|
[ADD] application: observable session, events facade, places and seats
The screens of iteration 3 need state they can subscribe to and commands
that keep the plan sound. The session follows the Svelte store contract,
unblocks a plan, cancels a gesture, keeps the framing, and orders the
warnings of a gesture. The facade lists events, settles the working folder
and runs copy, rename, import and delete. Places cover reservations, titles,
designation and the retained plan: each gesture reads seats as the display
shows them, reserved people keep their table, and a person removed frees
her chair while every other seat stays.
Checked: 1973 node, 127 browser, 60 node-long tests; coverage floors kept.
--- FR ---
[ADD] application : séance observable, façade des événements, places
Les écrans de l'itération 3 exigent un état auquel s'abonner et des
commandes qui gardent le plan sain. La séance suit le contrat des magasins
de Svelte, débloque un plan, annule un geste, garde le cadrage et ordonne
les avertissements d'un geste. La façade liste les événements, règle le
dossier de travail et mène copie, renommage, import et suppression. Les
places couvrent réservations, titres, désignation et plan retenu : chaque
geste lit les sièges comme l'écran les montre, une personne réservée garde
sa table, et une personne retirée libère sa chaise sans déplacer les autres.
Vérifié : 1973 node, 127 navigateur, 60 node-long ; seuils de couverture.
Assisted-by: Claude Opus 5.5
2026-10-07 04:14:24 -04:00
|
|
|
|
|
|
|
|
const avertissement = (code, details) => ({ code, details });
|
|
|
|
|
|
|
|
|
|
// L'instance de la charge, ou l'ErreurConfiguration qui la refuse :
|
|
|
|
|
// { instance } ou { refus }. Une autre erreur remonte.
|
|
|
|
|
function instanceDe(charge) {
|
|
|
|
|
try {
|
|
|
|
|
return { instance: normaliser(configurationDepuisCharge(charge)), refus: null };
|
|
|
|
|
} catch (erreur) {
|
|
|
|
|
if (!(erreur instanceof ErreurConfiguration)) throw erreur;
|
|
|
|
|
return { instance: null, refus: erreur };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Deux objets plats égaux champ pour champ : mêmes clés, mêmes valeurs.
|
|
|
|
|
function memesChamps(a, b) {
|
|
|
|
|
const cles = Object.keys(a);
|
|
|
|
|
return cles.length === Object.keys(b).length && cles.every((cle) => Object.hasOwn(b, cle) && Object.is(a[cle], b[cle]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Les raisons de dérive de chaque placement d'un examen : les propositions
|
|
|
|
|
// par identifiant croissant, puis le retenu sous la clé 'retenu'.
|
|
|
|
|
function raisonsParPlacement(examen) {
|
|
|
|
|
const raisons = new Map(examen.derives.map(({ id, raisons: liste }) => [id, liste]));
|
|
|
|
|
raisons.set('retenu', examen.retenu.raisons);
|
|
|
|
|
return raisons;
|
|
|
|
|
}
|
|
|
|
|
|
[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
|
|
|
// Les réservations au siège que le retenu, sièges attribués, ne tient pas à
|
|
|
|
|
// ce siège alors que sa personne est assise à la même table : celles qui
|
|
|
|
|
// tiennent une chaise selon la règle de l'affichage (placesTenues), dans la
|
|
|
|
|
// capacité courante. Par tour, dans l'ordre de retenu.tables, par siège ;
|
|
|
|
|
// occupant, la personne présente sur ce siège, null pour une chaise vide ou
|
|
|
|
|
// celle d'un absent. Une personne assise à une autre table relève de la
|
|
|
|
|
// règle de la table, que verifierInvariants juge.
|
|
|
|
|
function siegesNonTenus(charge, retenu, instance) {
|
|
|
|
|
if (!retenu.siegesAttribues) return [];
|
|
|
|
|
const actives = reservationsActives(charge);
|
|
|
|
|
const ids = presents(charge);
|
|
|
|
|
const enregistrementDe = new Map(charge.tables.map((enregistrement) => [enregistrement.id, enregistrement]));
|
|
|
|
|
const violations = [];
|
|
|
|
|
const lus = Math.min(retenu.tours, instance.R, retenu.placement.length);
|
|
|
|
|
for (let tour = 1; tour <= lus; tour += 1) {
|
|
|
|
|
const couvrantes = actives.filter((reservation) => couvre(reservation, tour));
|
|
|
|
|
retenu.tables.forEach((idTable, rang) => {
|
|
|
|
|
const enregistrement = enregistrementDe.get(idTable);
|
|
|
|
|
if (enregistrement === undefined || retenu.tables.indexOf(idTable) !== rang) return;
|
|
|
|
|
const liste = retenu.placement[tour - 1].sieges[rang] ?? [];
|
|
|
|
|
const { tenu } = placesTenues(
|
|
|
|
|
couvrantes.filter(({ table }) => table === idTable),
|
|
|
|
|
capacite(charge, enregistrement),
|
|
|
|
|
);
|
|
|
|
|
for (const siege of [...tenu.keys()].sort((a, b) => a - b)) {
|
|
|
|
|
const { participant } = tenu.get(siege);
|
|
|
|
|
const assis = liste[siege - 1] ?? null;
|
|
|
|
|
if (assis === participant || !liste.includes(participant)) continue;
|
|
|
|
|
const occupant = assis !== null && ids.has(assis) ? assis : null;
|
|
|
|
|
violations.push({ code: 'RESERVATION', participant, table: idTable, tour, siege, occupant });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return violations;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Les violations d'un retenu lisible (fautes vide) contre l'instance de la
|
|
|
|
|
* charge (§ 14.12) : celles de verifierInvariants, la réserve admise — des
|
|
|
|
|
* surnuméraires versés en réserve ne violent rien —, complétées de deux
|
|
|
|
|
* réservations non tenues qu'il ne relève pas. Une personne que le retenu
|
|
|
|
|
* ne place pas à un tour, et qu'une réservation impose à une table à ce
|
|
|
|
|
* tour, reçoit RESERVATION {participant, table, tour} juste après son
|
|
|
|
|
* NON_ASSIS : ajoutée ou réintégrée depuis la retenue, elle n'est honorée
|
|
|
|
|
* nulle part. Sièges attribués, une réservation au siège que le retenu
|
|
|
|
|
* donne à un autre, sa personne assise à la même table, reçoit RESERVATION
|
|
|
|
|
* {participant, table, tour, siege, occupant} (siegesNonTenus), après les
|
|
|
|
|
* autres. Le retenu se juge tel quel, sans retouche (§ 5.8).
|
|
|
|
|
*
|
|
|
|
|
* @param {import('../stockage/types.js').Charge} charge
|
|
|
|
|
* @param {import('../stockage/types.js').Retenu} retenu
|
|
|
|
|
* @param {import('../moteur/types.js').Instance} instance celle de la charge
|
|
|
|
|
* @returns {Object[]} les violations, dans cet ordre
|
|
|
|
|
*/
|
|
|
|
|
export function violationsDuRetenu(charge, retenu, instance) {
|
|
|
|
|
const { R, indexDe, idsTables, fixe } = instance;
|
|
|
|
|
const violations = [];
|
|
|
|
|
for (const violation of verifierInvariants(instance, planDepuisFichier(retenu), { reserveAutorisee: true })) {
|
|
|
|
|
violations.push(violation);
|
|
|
|
|
if (violation.code !== 'NON_ASSIS' || violation.tour > R) continue;
|
|
|
|
|
const imposee = fixe[indexDe.get(violation.participant) * R + violation.tour - 1];
|
|
|
|
|
if (imposee !== LIBRE) {
|
|
|
|
|
violations.push({ code: 'RESERVATION', participant: violation.participant, table: idsTables[imposee], tour: violation.tour });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return [...violations, ...siegesNonTenus(charge, retenu, instance)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Les violations du retenu cohérent d'une charge (violationsDuRetenu). []
|
|
|
|
|
// sans retenu, pour un retenu fautif, ou sans instance.
|
|
|
|
|
function violationsCourantes(charge, examen, instance) {
|
[ADD] application: observable session, events facade, places and seats
The screens of iteration 3 need state they can subscribe to and commands
that keep the plan sound. The session follows the Svelte store contract,
unblocks a plan, cancels a gesture, keeps the framing, and orders the
warnings of a gesture. The facade lists events, settles the working folder
and runs copy, rename, import and delete. Places cover reservations, titles,
designation and the retained plan: each gesture reads seats as the display
shows them, reserved people keep their table, and a person removed frees
her chair while every other seat stays.
Checked: 1973 node, 127 browser, 60 node-long tests; coverage floors kept.
--- FR ---
[ADD] application : séance observable, façade des événements, places
Les écrans de l'itération 3 exigent un état auquel s'abonner et des
commandes qui gardent le plan sain. La séance suit le contrat des magasins
de Svelte, débloque un plan, annule un geste, garde le cadrage et ordonne
les avertissements d'un geste. La façade liste les événements, règle le
dossier de travail et mène copie, renommage, import et suppression. Les
places couvrent réservations, titres, désignation et plan retenu : chaque
geste lit les sièges comme l'écran les montre, une personne réservée garde
sa table, et une personne retirée libère sa chaise sans déplacer les autres.
Vérifié : 1973 node, 127 navigateur, 60 node-long ; seuils de couverture.
Assisted-by: Claude Opus 5.5
2026-10-07 04:14:24 -04:00
|
|
|
if (charge.retenu === null || examen.retenu.fautes.length > 0 || instance === null) return [];
|
[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
|
|
|
return violationsDuRetenu(charge, charge.retenu, instance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Le nom affiché de la personne id dans la première charge qui la porte,
|
|
|
|
|
// ou null ; le numéro de la table id de même.
|
|
|
|
|
const nomDans = (id, charges) => {
|
|
|
|
|
for (const charge of charges) {
|
|
|
|
|
const trouvee = charge.participants.find((candidate) => candidate.id === id);
|
|
|
|
|
if (trouvee !== undefined) return nomAffiche(trouvee);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
};
|
|
|
|
|
const numeroDans = (id, charges) => {
|
|
|
|
|
for (const charge of charges) {
|
|
|
|
|
const trouvee = charge.tables.find((candidate) => candidate.id === id);
|
|
|
|
|
if (trouvee !== undefined) return trouvee.numero;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Les raisons de dérive nommées (§ 9) : chacune garde ses champs, et gagne
|
|
|
|
|
* personne, le nom affiché de la personne qu'elle désigne, et numero, le
|
|
|
|
|
* numéro de la table qu'elle désigne, lus dans la première des charges qui
|
|
|
|
|
* les porte ; une personne ou une table qu'aucune ne porte garde son seul
|
|
|
|
|
* identifiant. Rend des objets neufs.
|
|
|
|
|
*
|
|
|
|
|
* @param {Object[]} raisons
|
|
|
|
|
* @param {...import('../stockage/types.js').Charge} charges
|
|
|
|
|
* @returns {Object[]}
|
|
|
|
|
*/
|
|
|
|
|
export function raisonsNommees(raisons, ...charges) {
|
|
|
|
|
return raisons.map((raison) => {
|
|
|
|
|
const nommee = { ...raison };
|
|
|
|
|
if (raison.participant !== undefined) {
|
|
|
|
|
const personne = nomDans(raison.participant, charges);
|
|
|
|
|
if (personne !== null) nommee.personne = personne;
|
|
|
|
|
}
|
|
|
|
|
if (raison.table !== undefined) {
|
|
|
|
|
const numero = numeroDans(raison.table, charges);
|
|
|
|
|
if (numero !== null) nommee.numero = numero;
|
|
|
|
|
}
|
|
|
|
|
return nommee;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* L'examen d'une charge (examiner, S2), ses raisons de dérive nommées sur
|
|
|
|
|
* elle (raisonsNommees) : celles du retenu et de chaque proposition en
|
|
|
|
|
* dérive. Un objet neuf ; l'examen reçu ne change pas.
|
|
|
|
|
*
|
|
|
|
|
* @param {import('../stockage/placements.js').Examen} examen
|
|
|
|
|
* @param {import('../stockage/types.js').Charge} charge
|
|
|
|
|
* @returns {import('../stockage/placements.js').Examen}
|
|
|
|
|
*/
|
|
|
|
|
export function examenNomme(examen, charge) {
|
|
|
|
|
return {
|
|
|
|
|
...examen,
|
|
|
|
|
derives: examen.derives.map((derive) => ({ ...derive, raisons: raisonsNommees(derive.raisons, charge) })),
|
|
|
|
|
retenu: { ...examen.retenu, raisons: raisonsNommees(examen.retenu.raisons, charge) },
|
|
|
|
|
};
|
[ADD] application: observable session, events facade, places and seats
The screens of iteration 3 need state they can subscribe to and commands
that keep the plan sound. The session follows the Svelte store contract,
unblocks a plan, cancels a gesture, keeps the framing, and orders the
warnings of a gesture. The facade lists events, settles the working folder
and runs copy, rename, import and delete. Places cover reservations, titles,
designation and the retained plan: each gesture reads seats as the display
shows them, reserved people keep their table, and a person removed frees
her chair while every other seat stays.
Checked: 1973 node, 127 browser, 60 node-long tests; coverage floors kept.
--- FR ---
[ADD] application : séance observable, façade des événements, places
Les écrans de l'itération 3 exigent un état auquel s'abonner et des
commandes qui gardent le plan sain. La séance suit le contrat des magasins
de Svelte, débloque un plan, annule un geste, garde le cadrage et ordonne
les avertissements d'un geste. La façade liste les événements, règle le
dossier de travail et mène copie, renommage, import et suppression. Les
places couvrent réservations, titres, désignation et plan retenu : chaque
geste lit les sièges comme l'écran les montre, une personne réservée garde
sa table, et une personne retirée libère sa chaise sans déplacer les autres.
Vérifié : 1973 node, 127 navigateur, 60 node-long ; seuils de couverture.
Assisted-by: Claude Opus 5.5
2026-10-07 04:14:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const memeRaison = (code, cle, valeur) => (raison) => raison.code === code && raison[cle] === valeur;
|
|
|
|
|
|
|
|
|
|
// La raison de dérive qui nomme déjà la violation, ou undefined : la
|
|
|
|
|
// personne exclue, supprimée ou non placée ; la table supprimée, ajoutée, ou
|
|
|
|
|
// dont la capacité a changé ; le nombre de tours changé.
|
|
|
|
|
function raisonQuiLaNomme(violation, raisons) {
|
|
|
|
|
const { code, participant, table, detail } = violation;
|
|
|
|
|
if (code === 'EXCLU_PLACE') return raisons.find(memeRaison('PARTICIPANT_EXCLU', 'participant', participant));
|
|
|
|
|
if (code === 'INCONNU') return raisons.find(memeRaison('PARTICIPANT_SUPPRIME', 'participant', participant));
|
|
|
|
|
if (code === 'NON_ASSIS') return raisons.find(memeRaison('PARTICIPANT_NON_PLACE', 'participant', participant));
|
|
|
|
|
if (code === 'CAPACITE') return raisons.find(memeRaison('CAPACITE_CHANGEE', 'table', table));
|
|
|
|
|
if (code === 'TOURS') return raisons.find((raison) => raison.code === 'TOURS_CHANGES');
|
|
|
|
|
if (code === 'TABLE_INCONNUE' && detail === 'inconnue') return raisons.find(memeRaison('TABLE_SUPPRIMEE', 'table', table));
|
|
|
|
|
if (code === 'TABLE_INCONNUE' && detail === 'absente') return raisons.find(memeRaison('TABLE_AJOUTEE', 'table', table));
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Les violations du retenu de la charge que la dérive ne nomme pas déjà
|
|
|
|
|
* (§ 14.12, § 14.15) : INVARIANT_VIOLE {proposition, violations}, la
|
|
|
|
|
* proposition d'origine du retenu et les violations de verifierInvariants
|
|
|
|
|
* dans leur ordre, réserve admise ; null quand il n'en reste aucune, sans
|
|
|
|
|
* retenu, pour un retenu fautif, ou sur une configuration qui ne se
|
|
|
|
|
* normalise pas. Une réservation que le retenu ne tient pas en est le cas
|
[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
|
|
|
* ordinaire, à sa table ou à son siège, sa personne placée ou non
|
|
|
|
|
* (violationsDuRetenu) : la dérive ne compare pas les réservations.
|
[ADD] application: observable session, events facade, places and seats
The screens of iteration 3 need state they can subscribe to and commands
that keep the plan sound. The session follows the Svelte store contract,
unblocks a plan, cancels a gesture, keeps the framing, and orders the
warnings of a gesture. The facade lists events, settles the working folder
and runs copy, rename, import and delete. Places cover reservations, titles,
designation and the retained plan: each gesture reads seats as the display
shows them, reserved people keep their table, and a person removed frees
her chair while every other seat stays.
Checked: 1973 node, 127 browser, 60 node-long tests; coverage floors kept.
--- FR ---
[ADD] application : séance observable, façade des événements, places
Les écrans de l'itération 3 exigent un état auquel s'abonner et des
commandes qui gardent le plan sain. La séance suit le contrat des magasins
de Svelte, débloque un plan, annule un geste, garde le cadrage et ordonne
les avertissements d'un geste. La façade liste les événements, règle le
dossier de travail et mène copie, renommage, import et suppression. Les
places couvrent réservations, titres, désignation et plan retenu : chaque
geste lit les sièges comme l'écran les montre, une personne réservée garde
sa table, et une personne retirée libère sa chaise sans déplacer les autres.
Vérifié : 1973 node, 127 navigateur, 60 node-long ; seuils de couverture.
Assisted-by: Claude Opus 5.5
2026-10-07 04:14:24 -04:00
|
|
|
*
|
|
|
|
|
* @param {import('../stockage/types.js').Charge} charge
|
|
|
|
|
* @param {import('../stockage/placements.js').Examen} [examen] celui de la
|
|
|
|
|
* charge, examiner(charge) quand il manque
|
|
|
|
|
* @returns {{code: 'INVARIANT_VIOLE', details: {proposition: number, violations: object[]}}|null}
|
|
|
|
|
*/
|
|
|
|
|
export function invariantViole(charge, examen = examiner(charge)) {
|
|
|
|
|
const { instance } = instanceDe(charge);
|
|
|
|
|
const raisons = examen.retenu.raisons;
|
[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
|
|
|
const violations = violationsCourantes(charge, examen, instance).filter(
|
[ADD] application: observable session, events facade, places and seats
The screens of iteration 3 need state they can subscribe to and commands
that keep the plan sound. The session follows the Svelte store contract,
unblocks a plan, cancels a gesture, keeps the framing, and orders the
warnings of a gesture. The facade lists events, settles the working folder
and runs copy, rename, import and delete. Places cover reservations, titles,
designation and the retained plan: each gesture reads seats as the display
shows them, reserved people keep their table, and a person removed frees
her chair while every other seat stays.
Checked: 1973 node, 127 browser, 60 node-long tests; coverage floors kept.
--- FR ---
[ADD] application : séance observable, façade des événements, places
Les écrans de l'itération 3 exigent un état auquel s'abonner et des
commandes qui gardent le plan sain. La séance suit le contrat des magasins
de Svelte, débloque un plan, annule un geste, garde le cadrage et ordonne
les avertissements d'un geste. La façade liste les événements, règle le
dossier de travail et mène copie, renommage, import et suppression. Les
places couvrent réservations, titres, désignation et plan retenu : chaque
geste lit les sièges comme l'écran les montre, une personne réservée garde
sa table, et une personne retirée libère sa chaise sans déplacer les autres.
Vérifié : 1973 node, 127 navigateur, 60 node-long ; seuils de couverture.
Assisted-by: Claude Opus 5.5
2026-10-07 04:14:24 -04:00
|
|
|
(violation) => raisonQuiLaNomme(violation, raisons) === undefined,
|
|
|
|
|
);
|
|
|
|
|
if (violations.length === 0) return null;
|
|
|
|
|
return avertissement('INVARIANT_VIOLE', { proposition: charge.retenu.proposition, violations });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Avertissements d'un geste, de la charge d'avant à celle d'après (§ 5.9,
|
|
|
|
|
* § 9), dans cet ordre. Aucun ne lève sur un placement : les raisons se
|
|
|
|
|
* lisent sur examiner(avant) et examiner(apres) (S2), et planDepuisFichier
|
|
|
|
|
* ne reçoit le retenu que quand examiner(…).retenu.fautes est vide.
|
|
|
|
|
*
|
|
|
|
|
* CONFIGURATION_INCOHERENTE {code, details} normaliser(configurationDepuisCharge(apres))
|
|
|
|
|
* lève, et celle d'avant se normalisait ; PLACES_MANQUANTES et
|
|
|
|
|
* RESERVATION_NON_HONOREE, qui lisent l'instance d'après, ne se calculent
|
|
|
|
|
* alors pas ;
|
|
|
|
|
* PLACES_MANQUANTES {placesManquantes} nombrePlacesManquantes de l'instance
|
|
|
|
|
* d'après, non nul et plus grand que celui d'avant (0 quand avant ne se
|
|
|
|
|
* normalisait pas) ;
|
|
|
|
|
* DERIVE_NOUVELLE {touchees: [{id|'retenu', raisons}]} par placement, les
|
|
|
|
|
* raisons d'examiner(apres) — derives, retenu.raisons — qu'examiner(avant)
|
[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
|
|
|
* ne portait pas, comparées champ pour champ, puis nommées sur la charge
|
|
|
|
|
* d'après, ou d'avant pour ce que le geste retire (raisonsNommees) ; les
|
|
|
|
|
* propositions par identifiant, puis le retenu, sous id 'retenu' ;
|
[FIX] plan: named warning, one places state, highlight, table spacing
The unheld-reservation warning names the person and the table number
instead of their identifiers. The places state is computed once per change
and handed to the side panels, not once per panel. A person can be
highlighted from their menu or from the grid, and the view bar names them.
A created table takes a cell a full pitch away from every table, its own
capacity included, so no name list runs over a neighbour's chairs. The
rendering guards fail on an empty walk and also check focus and selection.
Checked: 2692 node, 496 browser, 60 long tests, from the index alone.
--- FR ---
[FIX] plan : avertissement nommé, état des places unique, évidence, pas
L'avertissement de réservation non honorée nomme la personne et le numéro
de la table plutôt que leurs identifiants. L'état des places se calcule une
fois par changement et passe aux panneaux, non une fois par panneau. Une
personne se met en évidence par son menu ou depuis la grille, et la barre
de vue la nomme. Une table créée prend une case à un pas plein de chaque
table, sa capacité comprise : aucune liste ne court sur les chaises
voisines. Les gardes du rendu échouent sur un parcours vide et éprouvent
aussi le focus et la sélection. Vérifié : 2692 node, 496 navigateur, 60.
Assisted-by: Claude Opus 5.5
2026-10-07 15:05:01 -04:00
|
|
|
* RESERVATION_NON_HONOREE {participant, table, tour, personne, numero}
|
[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
|
|
|
* chaque violation RESERVATION de violationsDuRetenu(apres, apres.retenu,
|
|
|
|
|
* instance d'après) absente du même calcul sur avant, qui n'en compte
|
|
|
|
|
* aucune quand son retenu est nul ou fautif, ou que sa configuration ne
|
|
|
|
|
* se normalisait pas ; personne est le nom affiché du participant,
|
|
|
|
|
* numero celui de la table, lus sur la charge d'après, qui porte l'une et
|
|
|
|
|
* l'autre puisque l'instance qui les viole en vient. Au siège, les
|
|
|
|
|
* détails portent en plus siege et occupant, ceux de la violation : le
|
|
|
|
|
* geste qui la lève est l'échange de la personne avec l'occupant
|
|
|
|
|
* (echangerDansRetenu), ou, chaise vide, son déplacement au siège.
|
[ADD] application: observable session, events facade, places and seats
The screens of iteration 3 need state they can subscribe to and commands
that keep the plan sound. The session follows the Svelte store contract,
unblocks a plan, cancels a gesture, keeps the framing, and orders the
warnings of a gesture. The facade lists events, settles the working folder
and runs copy, rename, import and delete. Places cover reservations, titles,
designation and the retained plan: each gesture reads seats as the display
shows them, reserved people keep their table, and a person removed frees
her chair while every other seat stays.
Checked: 1973 node, 127 browser, 60 node-long tests; coverage floors kept.
--- FR ---
[ADD] application : séance observable, façade des événements, places
Les écrans de l'itération 3 exigent un état auquel s'abonner et des
commandes qui gardent le plan sain. La séance suit le contrat des magasins
de Svelte, débloque un plan, annule un geste, garde le cadrage et ordonne
les avertissements d'un geste. La façade liste les événements, règle le
dossier de travail et mène copie, renommage, import et suppression. Les
places couvrent réservations, titres, désignation et plan retenu : chaque
geste lit les sièges comme l'écran les montre, une personne réservée garde
sa table, et une personne retirée libère sa chaise sans déplacer les autres.
Vérifié : 1973 node, 127 navigateur, 60 node-long ; seuils de couverture.
Assisted-by: Claude Opus 5.5
2026-10-07 04:14:24 -04:00
|
|
|
*
|
|
|
|
|
* @param {import('../stockage/types.js').Charge} avant
|
|
|
|
|
* @param {import('../stockage/types.js').Charge} apres
|
|
|
|
|
* @returns {Array<{code: string, details: Object}>}
|
|
|
|
|
*/
|
|
|
|
|
export function avertissementsApres(avant, apres) {
|
|
|
|
|
const rendus = [];
|
|
|
|
|
const examenAvant = examiner(avant);
|
|
|
|
|
const examenApres = examiner(apres);
|
|
|
|
|
const instanceAvant = instanceDe(avant).instance;
|
|
|
|
|
const { instance, refus } = instanceDe(apres);
|
|
|
|
|
|
|
|
|
|
if (refus !== null && instanceAvant !== null) {
|
|
|
|
|
rendus.push(avertissement('CONFIGURATION_INCOHERENTE', { code: refus.code, details: refus.details }));
|
|
|
|
|
}
|
|
|
|
|
if (instance !== null) {
|
|
|
|
|
const manque = nombrePlacesManquantes(instance);
|
|
|
|
|
const manqueAvant = instanceAvant === null ? 0 : nombrePlacesManquantes(instanceAvant);
|
|
|
|
|
if (manque > 0 && manque > manqueAvant) rendus.push(avertissement('PLACES_MANQUANTES', { placesManquantes: manque }));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const anciennes = raisonsParPlacement(examenAvant);
|
|
|
|
|
const touchees = [];
|
|
|
|
|
for (const [id, raisons] of raisonsParPlacement(examenApres)) {
|
|
|
|
|
const connues = anciennes.get(id) ?? [];
|
|
|
|
|
const nouvelles = raisons.filter((raison) => !connues.some((connue) => memesChamps(connue, raison)));
|
[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
|
|
|
if (nouvelles.length > 0) touchees.push({ id, raisons: raisonsNommees(nouvelles, apres, avant) });
|
[ADD] application: observable session, events facade, places and seats
The screens of iteration 3 need state they can subscribe to and commands
that keep the plan sound. The session follows the Svelte store contract,
unblocks a plan, cancels a gesture, keeps the framing, and orders the
warnings of a gesture. The facade lists events, settles the working folder
and runs copy, rename, import and delete. Places cover reservations, titles,
designation and the retained plan: each gesture reads seats as the display
shows them, reserved people keep their table, and a person removed frees
her chair while every other seat stays.
Checked: 1973 node, 127 browser, 60 node-long tests; coverage floors kept.
--- FR ---
[ADD] application : séance observable, façade des événements, places
Les écrans de l'itération 3 exigent un état auquel s'abonner et des
commandes qui gardent le plan sain. La séance suit le contrat des magasins
de Svelte, débloque un plan, annule un geste, garde le cadrage et ordonne
les avertissements d'un geste. La façade liste les événements, règle le
dossier de travail et mène copie, renommage, import et suppression. Les
places couvrent réservations, titres, désignation et plan retenu : chaque
geste lit les sièges comme l'écran les montre, une personne réservée garde
sa table, et une personne retirée libère sa chaise sans déplacer les autres.
Vérifié : 1973 node, 127 navigateur, 60 node-long ; seuils de couverture.
Assisted-by: Claude Opus 5.5
2026-10-07 04:14:24 -04:00
|
|
|
}
|
|
|
|
|
if (touchees.length > 0) rendus.push(avertissement('DERIVE_NOUVELLE', { touchees }));
|
|
|
|
|
|
|
|
|
|
const reservations = (charge, examen, inst) =>
|
[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
|
|
|
violationsCourantes(charge, examen, inst).filter(({ code }) => code === 'RESERVATION');
|
[ADD] application: observable session, events facade, places and seats
The screens of iteration 3 need state they can subscribe to and commands
that keep the plan sound. The session follows the Svelte store contract,
unblocks a plan, cancels a gesture, keeps the framing, and orders the
warnings of a gesture. The facade lists events, settles the working folder
and runs copy, rename, import and delete. Places cover reservations, titles,
designation and the retained plan: each gesture reads seats as the display
shows them, reserved people keep their table, and a person removed frees
her chair while every other seat stays.
Checked: 1973 node, 127 browser, 60 node-long tests; coverage floors kept.
--- FR ---
[ADD] application : séance observable, façade des événements, places
Les écrans de l'itération 3 exigent un état auquel s'abonner et des
commandes qui gardent le plan sain. La séance suit le contrat des magasins
de Svelte, débloque un plan, annule un geste, garde le cadrage et ordonne
les avertissements d'un geste. La façade liste les événements, règle le
dossier de travail et mène copie, renommage, import et suppression. Les
places couvrent réservations, titres, désignation et plan retenu : chaque
geste lit les sièges comme l'écran les montre, une personne réservée garde
sa table, et une personne retirée libère sa chaise sans déplacer les autres.
Vérifié : 1973 node, 127 navigateur, 60 node-long ; seuils de couverture.
Assisted-by: Claude Opus 5.5
2026-10-07 04:14:24 -04:00
|
|
|
const tenues = reservations(avant, examenAvant, instanceAvant);
|
[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
|
|
|
for (const violation of reservations(apres, examenApres, instance)) {
|
|
|
|
|
const { participant, table, tour, siege = null } = violation;
|
|
|
|
|
const dejaLa = tenues.some(
|
|
|
|
|
(connue) =>
|
|
|
|
|
connue.participant === participant && connue.table === table && connue.tour === tour && (connue.siege ?? null) === siege,
|
|
|
|
|
);
|
[FIX] plan: named warning, one places state, highlight, table spacing
The unheld-reservation warning names the person and the table number
instead of their identifiers. The places state is computed once per change
and handed to the side panels, not once per panel. A person can be
highlighted from their menu or from the grid, and the view bar names them.
A created table takes a cell a full pitch away from every table, its own
capacity included, so no name list runs over a neighbour's chairs. The
rendering guards fail on an empty walk and also check focus and selection.
Checked: 2692 node, 496 browser, 60 long tests, from the index alone.
--- FR ---
[FIX] plan : avertissement nommé, état des places unique, évidence, pas
L'avertissement de réservation non honorée nomme la personne et le numéro
de la table plutôt que leurs identifiants. L'état des places se calcule une
fois par changement et passe aux panneaux, non une fois par panneau. Une
personne se met en évidence par son menu ou depuis la grille, et la barre
de vue la nomme. Une table créée prend une case à un pas plein de chaque
table, sa capacité comprise : aucune liste ne court sur les chaises
voisines. Les gardes du rendu échouent sur un parcours vide et éprouvent
aussi le focus et la sélection. Vérifié : 2692 node, 496 navigateur, 60.
Assisted-by: Claude Opus 5.5
2026-10-07 15:05:01 -04:00
|
|
|
if (dejaLa) continue;
|
|
|
|
|
const personne = nomAffiche(apres.participants.find(({ id }) => id === participant));
|
|
|
|
|
const { numero } = apres.tables.find(({ id }) => id === table);
|
[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
|
|
|
const auSiege = siege === null ? {} : { siege, occupant: violation.occupant };
|
|
|
|
|
rendus.push(avertissement('RESERVATION_NON_HONOREE', { participant, table, tour, personne, numero, ...auSiege }));
|
[ADD] application: observable session, events facade, places and seats
The screens of iteration 3 need state they can subscribe to and commands
that keep the plan sound. The session follows the Svelte store contract,
unblocks a plan, cancels a gesture, keeps the framing, and orders the
warnings of a gesture. The facade lists events, settles the working folder
and runs copy, rename, import and delete. Places cover reservations, titles,
designation and the retained plan: each gesture reads seats as the display
shows them, reserved people keep their table, and a person removed frees
her chair while every other seat stays.
Checked: 1973 node, 127 browser, 60 node-long tests; coverage floors kept.
--- FR ---
[ADD] application : séance observable, façade des événements, places
Les écrans de l'itération 3 exigent un état auquel s'abonner et des
commandes qui gardent le plan sain. La séance suit le contrat des magasins
de Svelte, débloque un plan, annule un geste, garde le cadrage et ordonne
les avertissements d'un geste. La façade liste les événements, règle le
dossier de travail et mène copie, renommage, import et suppression. Les
places couvrent réservations, titres, désignation et plan retenu : chaque
geste lit les sièges comme l'écran les montre, une personne réservée garde
sa table, et une personne retirée libère sa chaise sans déplacer les autres.
Vérifié : 1973 node, 127 navigateur, 60 node-long ; seuils de couverture.
Assisted-by: Claude Opus 5.5
2026-10-07 04:14:24 -04:00
|
|
|
}
|
|
|
|
|
return rendus;
|
|
|
|
|
}
|