From dd7ad19cc9bb6b839ee61e887d5270cef0280a18 Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Wed, 7 Oct 2026 16:04:52 -0400 Subject: [PATCH] [UPD] spec: follow the code and the iteration 3 decisions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spec now states what the code does: nothing persists between sessions under Electron, the seat plan is planning and a removed person frees her chair, the ranked table shows the minimum of encounters and r(p) by its sum, refusals with no remedy form a named class, the diagnostic says what would make a conflict avoidable while the quality segment never does, the geometry layer is guarded on its own, and created tables keep name lists off their neighbours. Checked against each module and its tests; the version check passes all eight points of 18.5. --- FR --- [UPD] spec : suivre le code et les décisions de l'itération 3 Le spec dit ce que fait le code : rien ne persiste d'une séance à l'autre sous Electron, le plan de places est une planification et une personne retirée libère sa chaise, le tableau classé montre le minimum des rencontres et r(p) par sa somme, les refus sans remède forment une classe nommée, le diagnostic dit ce qui rendrait un conflit évitable et le segment de qualité jamais, la géométrie est une couche gardée à part, et une table créée garde les listes loin des voisines. Vérifié contre chaque module et ses épreuves ; le contrôle de version passe les huit points du § 18.5. Assisted-by: Claude Opus 5.5 --- spec.md | 233 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 173 insertions(+), 60 deletions(-) diff --git a/spec.md b/spec.md index 41973fe..bd0c749 100644 --- a/spec.md +++ b/spec.md @@ -61,10 +61,11 @@ Aucun des deux ne dépend de l'étape atteinte. jamais l'un sans l'autre (§ 8.2) ; 2. il se reprend par un retour à un instant, et le journal ne se tronque jamais (§ 8.3) ; -3. s'il est refusé, le refus nomme sa cause et le geste qui la lève, **là où le - geste a eu lieu** : sur la place pour un geste du plan (§ 5.9), dans - l'aperçu d'import pour une ligne de CSV (§ 10.1), sur le champ pour une - saisie. Seul un geste qui détruit de la saisie ouvre une fenêtre à confirmer. +3. s'il est refusé, le refus nomme sa cause et, quand un geste la lève, ce + geste (§ 5.9), **là où le geste a eu lieu** : sur la place pour un geste du + plan, dans l'aperçu d'import pour une ligne de CSV (§ 10.1), sur le champ + pour une saisie. Seul un geste qui détruit de la saisie ouvre une fenêtre à + confirmer. Les étapes 8 et 10 — lire le diagnostic, comparer — ne modifient rien et restent vivantes en lecture (§ 8.4). @@ -102,9 +103,10 @@ en bloc une baisse qu'une seule table refuse (§ 6.1). retrouve les **ancrages** intacts, parce que la portée « tous les tours » n'est jamais développée (§ 4.3). La protection s'arrête là, et le logiciel le dit **avant** d'appliquer : retirer le tour *r* détruit les réservations de portée -« tour désigné » portant sur *r*, et les tours au-delà de *r* des placements -déjà engendrés. Les annoncer après coup ferait découvrir la perte à -l'impression. +« tour désigné » portant sur *r*. Les placements déjà engendrés, eux, ne sont +pas tronqués : ils ne portent plus le nombre de tours de la soirée, restent +entiers **en dérive** (§ 9), et le logiciel nomme ceux que le changement +touche. Les annoncer après coup ferait découvrir la perte à l'impression. **6. Désigner les animateurs, table par table.** *Facultative — une soirée sans aucun animateur est une configuration valide, et la petite démonstration en est @@ -391,10 +393,9 @@ une lecture et non un jugement : | **manque** | plafond réalisé − rencontres (§ 5.5) — la grandeur qui compare deux propositions (§ 12.10) | | **écart d'itinéraire** | plafond a priori − plafond réalisé (§ 5.5, § 12.10) | -**Les agrégats portent sur tous les participants placés.** Le minimum et la -moyenne se calculent sur l'ensemble, ancrés compris, et **deux lignes -secondaires** donnent la même mesure restreinte aux **mobiles** et aux -**ancrés**. Un participant partiellement fixé compte parmi les mobiles. +**Les agrégats portent sur tous les participants placés.** Le minimum se +calcule sur l'ensemble, ancrés compris, et **deux lignes secondaires** donnent +la même mesure restreinte aux **mobiles** et aux **ancrés**. Un participant partiellement fixé compte parmi les mobiles. > Un ancré n'est pas structurellement désavantagé : à table de 8 avec un seul > ancré et R = 4, son plafond vaut 28, exactement celui d'un mobile visitant @@ -404,8 +405,16 @@ secondaires** donnent la même mesure restreinte aux **mobiles** et aux > global désigne un défaut qu'une relance corrige, ou la conséquence de son > propre plan de réservation. -**Le minimum compte plus que la moyenne.** Il décrit le sort de la personne la -plus mal servie, qui est celle qui se plaindra. +**Des rencontres, le minimum s'affiche, jamais la moyenne.** Le minimum décrit +le sort de la personne la plus mal servie, qui est celle qui se plaindra. La +moyenne ne sépare rien : quand les tables sont pleines à chaque tour, le nombre +de voisinages créés est fixé par le mobilier, et la moyenne est la même pour +toutes les propositions (§ 12.8). + +**La redondance se lit par sa somme**, Σ r(p), la grandeur que la recherche et +le classement lisent (§ 5.7). Elle va dans l'autre sens que les autres +colonnes — plus elle est grande, pire est le sort —, et son minimum désignerait +la personne la mieux servie. **Les deux unités de collision ne se mélangent jamais.** Un chiffre de collision cité quelque part — § 5.6, § 12.4, § 15.3, une étape du pilotage — **nomme son @@ -668,6 +677,12 @@ Une fois un placement retenu, le même geste déplace une personne réelle. **Le geste est identique ; ce qui change est l'état des données**, et l'interface le dit, pour que l'opérateur sache lequel des deux il fait. +**Le placement se prépare, il ne suit pas la salle.** Retirer une personne du +placement retenu libère sa chaise, et personne d'autre ne change de siège ni de +table : la chaise reste vide jusqu'à ce qu'un geste y assoie quelqu'un, et un +geste n'assied que les personnes qu'il nomme. Quand les sièges sont attribués, le +fichier écrit cette chaise vide à sa place (§ 8.9). + **Il n'existe aucune commande qui répartit les animateurs sur les tables.** L'opérateur désigne lui-même quelle personne anime quelle table (§ 2.1, étape 6). Une commande qui attribuerait un animateur par numéro de table le @@ -715,6 +730,17 @@ Un refus **nomme sa cause et propose le geste qui le lève**, et se manifeste détruit de la saisie ouvre une fenêtre à confirmer : une suite de modales apprend à cliquer sans lire, et le premier refus qui comptait passe inaperçu. +**Quand aucun geste ne lève le refus, il nomme sa cause seule.** Ainsi d'une +valeur qui se corrige dans le champ même, dont le texte dit la valeur attendue — +moins de deux sièges, une saisie non entière, moins d'un tour, un libellé ou un +nom vides ; d'une cible absente ou disparue entre-temps — une personne, une +proposition, une réservation, un titre, des réservations à convertir —, +qu'aucune commande ne fait revenir et sur laquelle l'interface n'offre pas le +geste ; d'un compteur au bout de sa règle, d'un plan qui n'est plus bloqué, d'un +geste sans effet, et d'un refus du CSV relayé par l'import, qui se lève dans le +fichier. Un remède posé pour la forme enverrait l'opérateur vers un geste qui ne +change rien. + ### 5.10 Le coût d'évaluation A(p) et r(p) demandent de parcourir les personnes rencontrées par chacun. @@ -737,15 +763,20 @@ d'écran (§ 19.4) tomberait avec. L'interdit de `performance.now` dans le moteu **Le compte est un réglage, et son plafond d'usage est de trente minutes.** Il est exposé dans les réglages de génération, avec son unité ; le logiciel affiche -à côté la **durée réellement observée du dernier calcul sur cette machine**, qui -est la seule façon d'étalonner un compte. Le réglage livré par défaut est celui -qui, sur la machine de référence, reste bien en deçà de ce plafond. +à côté la **durée réellement observée du dernier calcul de la séance**, qui est +la seule façon d'étalonner un compte. Elle vaut pour la séance et ne se garde +pas au-delà — rien ne survit à la séance hors du dossier de travail (§ 8.6) : au +premier calcul d'un lancement, aucune mesure n'existe, et l'estimation se dit +inconnue. Le réglage livré par défaut est celui qui, sur la machine de +référence, reste bien en deçà de ce plafond. **Une génération longue s'annonce avant de partir.** À partir de la dernière durée mesurée, le logiciel énonce l'ordre de grandeur attendu — « environ vingt -minutes à ce réglage » — et demande. Une recherche d'une demi-heure lancée par -mégarde est une demi-heure de soirée perdue, et aucun réglage par défaut ne -protège de cela. +minutes à ce réglage » — et, **au-delà d'une minute estimée**, demande, par une +question posée en place, sans fenêtre. Sans mesure, il demande dès que les +mouvements demandés — propositions × compte d'arrêt — dépassent dix fois ceux du +réglage par défaut. Une recherche d'une demi-heure lancée par mégarde est une +demi-heure de soirée perdue, et aucun réglage par défaut ne protège de cela. **Pendant la recherche, l'application reste vivante.** Le calcul ne tient pas le fil d'exécution de l'interface : le plan reste lisible, la page de qualité des @@ -821,10 +852,16 @@ table refuse, l'opération entière est refusée, nommément, et rien ne change. sièges disparaissent par numéro décroissant ; le refus les liste. - Une capacité non entière, négative, ou saisie en texte. -Deux cas **avertissent sans refuser** : réduire sous le nombre de personnes -assises (les surnuméraires vont dans la réserve visible, nommément listées, -jamais effacées en silence) ; et dépasser le nombre de sièges au-delà duquel le -dessin cesse d'être lisible — seuil **mesuré** au sens du § 14.1. +Deux cas **avertissent sans refuser** : réduire **par le champ** sous le nombre +de personnes assises (les surnuméraires vont dans la réserve visible, nommément +listées, jamais effacées en silence) ; et dépasser le nombre de sièges au-delà +duquel le dessin cesse d'être lisible — seuil **mesuré** au sens du § 14.1. + +**Le champ avertit, la poignée refuse.** Saisir une capacité est un geste +délibéré, fait en lisant le nombre ; tirer une poignée est un geste de +géométrie, fait sans regarder les autres tours : la même réduction y est refusée +(§ 7.1). Un changement de défaut (§ 6.1) se contrôle, table par table, comme une +saisie au champ. --- @@ -840,7 +877,7 @@ l'opérateur agit directement dessus. | cliquer une chaise | sélectionne la place — l'assigner, la réserver, lui donner un titre | | glisser une personne sur un siège libre | la déplace | | glisser une personne sur une autre | les échange | -| glisser une personne hors des tables | la retire du tour ; elle attend dans la **réserve** visible | +| glisser une personne hors des tables | la retire du tour ; elle attend dans la **réserve** visible, et sa chaise reste vide (§ 5.8) | | glisser une table | change sa position | | tirer la poignée d'une table | **change son nombre de places** | | survoler une table en conflit | affiche le détail des règles violées | @@ -858,7 +895,13 @@ chaises apparaissent et disparaissent sous le pointeur. **La poignée refuse de descendre sous le nombre de sièges occupés, tous tours confondus** — sinon un geste de géométrie désassoit deux personnes au troisième tour, que l'opérateur ne regarde pas. Le logiciel nomme le nombre bloquant et le -tour concerné. +tour concerné. Le champ de capacité, saisie délibérée, accepte la même réduction +et l'annonce (§ 6.2). + +**Une personne qu'une réservation tient à sa table ne se retire pas du tour.** +Le refus nomme la réservation et offre « Retirer la réservation » : une +réservation se défait par sa propre commande, jamais en passant par un +glissement. **La rotation d'une table carrée n'existe pas dans la première itération** : elle introduirait une orientation dans la numérotation des sièges et dans la @@ -897,7 +940,10 @@ unités, et le plan répondrait faux partout. Une épreuve en navigateur confronte la fonction pure à `getScreenCTM().inverse()`. Ce n'est pas une seconde implémentation : c'est un -**oracle** fourni par le moteur de rendu. +**oracle** fourni par le moteur de rendu. L'écart admis est d'**un millième de +pixel d'écran** : le moteur de rendu lit les nombres de l'attribut `transform` +en flottants de 32 bits et compose sa matrice à cette précision, quand une +violation de l'un des trois invariants décale le plan d'un pixel au moins. **Le zoom se fait sous le curseur**, sinon le contenu fuit vers un coin et l'opérateur poursuit la table qu'il visait. @@ -955,6 +1001,13 @@ et la table devient la cible**, le siège se choisissant dans son panneau. Le logiciel le montre en cessant de dessiner les chaises individuellement, plutôt qu'en laissant l'opérateur manquer sa cible sans comprendre. +**Le seuil se décide table par table**, sur le pas de chacune — la distance +entre deux sièges voisins au bord du plateau. Au même zoom, une petite table +ronde, dont le plancher du § 7.7 écarte les sièges de plus de 60 cm, garde ses +sièges pour cibles quand ses voisines de 8 n'en ont plus. Un seuil unique, réglé +sur la table la plus serrée, retirerait ses sièges à une table qui les montre +pointables. + **Il n'y a pas de survol au doigt** : le détail d'un conflit est accessible par survol, par focus clavier **et par pression longue** — un seul composant d'infobulle, trois déclencheurs. @@ -1033,8 +1086,9 @@ diamètre = max(70, places × 60 / π) en centimètres ``` Soit 115 cm pour 6 places, 153 pour 8, 191 pour 10. **Le plancher n'est pas -cosmétique** : en deçà de six convives ce n'est plus le périmètre qui borne la -table mais le plateau, et la formule seule dessinerait des guéridons. Les deux +cosmétique** : en deçà de quatre convives — la formule atteint 70 cm à 3,67 +places — ce n'est plus le périmètre qui borne la table mais le plateau, et la +formule seule dessinerait des guéridons. Les deux valeurs sont des **réglages par défaut, non des normes vérifiées** ; un diamètre saisi à la main l'emporte. @@ -1043,6 +1097,19 @@ noms couvre plusieurs mètres carrés fictifs. **Le plan à l'échelle du bâtim est le plan listes masquées**, et le logiciel le dit sur chaque impression portant les listes. +**Le bloc de noms d'une table se pose à droite de son emprise** — le plateau et +ses chaises —, à 36 cm d'elle : l'écart laisse passer le contour de focus de la +table sans qu'aucune marque couvre la liste. Sa largeur est fixée dans le +dessin, et un nom trop long s'y abrège (§ 7.4). **Aucune liste ne passe sur les +chaises d'une voisine posée sur la grille** : une table créée prend la première +case libre d'une grille dont les colonnes s'écartent d'une emprise, de deux +écarts et d'un bloc de noms, à un pas entier au moins, sur l'un des deux axes, de +toute table déjà posée, et les démonstrations (§ 15) sont rangées sur la même +grille. Le prix est la place : au +zoom ajusté, une grande salle descend sous le seuil qui retire les listes +(§ 17, point 6), et un grand événement peut s'ouvrir sans listes de noms, qui se +dessinent quand l'opérateur rapproche la vue. + **Tant qu'aucune dimension de salle n'est saisie, le plan est exact dans ses tables et arbitraire dans son cadre.** Le logiciel porte alors, sur le plan et sur **chaque impression**, la mention « disposition relative — l'encombrement @@ -1201,6 +1268,14 @@ qu'un calcul tourne. Le retour **automatique** ne peut donc jamais tomber pendant un geste ; le retour **explicite**, lui, annule un glissement en cours comme le ferait un `pointercancel`. +**Est une activité la fin d'un geste**, qui relance le compte : un geste achevé +ou refusé, une saisie validée ou abandonnée, une fenêtre à confirmer refermée, +et tout appui relâché sur le plan — un clic qui n'exécute rien et un déplacement +de vue compris. Regarder sans appuyer n'en est pas une : zoomer à la molette, +une commande de vue, changer de tour affiché ne relancent rien. Le retour +automatique se voit au cadre, au libellé et au bandeau, et un avertissement non +modal le dit jusqu'au passage en écriture suivant. + **Le mode est visible sur la surface de travail elle-même** — un cadre et un libellé permanents autour du plan — et non dans un coin de barre d'outils : l'opérateur regarde le plan. @@ -1299,7 +1374,9 @@ règle écrite, et l'affiche : sauvegarde est la copie d'un seul dossier. 5. L'épreuve échoue, ou le point 2 l'a interrompue → le dossier de travail est un dossier nommé d'après le produit, dans les *Documents* de l'opérateur. Le - logiciel **dit pourquoi**, une fois, à la première ouverture, sans bloquer. + logiciel **dit pourquoi**, une fois par séance, sans bloquer : s'en souvenir + d'une séance à l'autre demanderait un réglage local de plus, et le § 8.5 les + borne à deux. **Le dossier retenu est éprouvé à son tour, et c'est cette épreuve qui le crée** : le dossier des *Documents* naît à la détermination, avant que la liste @@ -1454,7 +1531,8 @@ plateforme**. parce que l'enregistrement automatique la rend définitive en une seconde. - **Version de format.** Un fichier **plus récent** s'ouvre en lecture seule sans passage possible en écriture ; un fichier **plus ancien** se convertit au - premier passage en écriture, jamais à l'ouverture. + premier geste qui l'écrit, jamais à l'ouverture ni au passage en écriture, qui + ne réécrit pas le fichier d'état. - **Une seule séance en écriture**, le verrou se prenant **à l'entrée en mode écriture** et non à l'ouverture. - **Contrôle de cohérence** : l'en-tête annonce ses comptes, sa révision, sa @@ -2342,9 +2420,10 @@ perd ?* **Le minimum gouverne la page** : chaque vue place le cas le plus défavorable à une position **fixe et prévisible** — le premier point, la première ligne — -jamais là où il faut le chercher. La moyenne l'accompagne en encre secondaire et -n'apparaît jamais seule. Un placement où chacun rencontre 27 personnes sauf une -qui en rencontre 14 a une excellente moyenne et un problème. +jamais là où il faut le chercher. La moyenne des rencontres ne s'affiche pas : à +tables pleines, elle est la même pour toutes les propositions (§ 12.8). Un +placement où chacun rencontre 27 personnes sauf une qui en rencontre 14 a une +excellente moyenne et un problème. ### 12.2 L'en-tête chiffré @@ -2452,7 +2531,10 @@ et deux tris opposés dans une même page se contredisent devant l'opérateur. relâchant les contraintes : c'est une **borne inférieure**, jamais un fait. Nommer « évitable » le complément affirmerait qu'un meilleur placement le retire, et condamnerait l'opérateur à relancer indéfiniment sur un conflit -qu'aucun placement ne retire. +qu'aucun placement ne retire. Le mot garde son sens dans les remèdes du +diagnostic (§ 5.6), et là seulement : une table de plus, ou une appartenance +répartie autrement, « la rend évitable » parce qu'elle change la +**configuration** — jamais parce qu'une relance ferait mieux. **Les participants sans appartenance ne forment pas un groupe** : sinon un pseudo-groupe de quarante personnes produit la plus longue barre, un plancher @@ -2864,6 +2946,12 @@ doit afficher une version et non une importation manquante, et **contrôlé par rejeu du script**, parce qu'un fichier engendré et oublié affiche une version périmée avec l'assurance d'une constante. +**Ce qui n'est pas un composant s'éprouve sous `node`** : `src/application` et +les modules purs de `src/interface` — tri, filtre, mise en forme, modèle de +dessin, navigation au clavier — entrent dans le projet `node` du § 14.8, à côté +du moteur ; seuls les composants Svelte, et ce qu'ils peignent, passent au +navigateur. + ### 13.2 Une seule langue, et c'est une exigence Tout — le moteur, la géométrie, l'interface — est écrit en **JavaScript**. @@ -2936,8 +3024,13 @@ message d'erreur**. listes, il rend des placements. C'est ce qui le rend testable sous `node`, en quelques secondes — et c'est la condition pour qu'il soit éprouvé sérieusement. -**La géométrie du plan** est elle aussi un module de **fonctions pures**, séparé -du rendu. +**La géométrie du plan** est une couche à part, de **fonctions pures**, séparée +du rendu et placée plus bas que le moteur : elle n'importe ni le moteur, ni +l'analyseur CSV, ni le générateur de démonstrations, ni l'application, ni +l'interface, ni le stockage, et ne touche pas le navigateur. Elle est +**requise** : sa garde échoue quand son arbre ne fournit aucun module. Le dessin, +la désignation d'un siège et le dépôt partagent ses conversions et ses chaises +(§ 7.2, § 7.3). Les **deux frontières de plateforme** sont le système de fichiers et l'impression : une interface unique, deux implémentations — plus, pour le système @@ -2958,9 +3051,12 @@ ou de `src/geometrie` importe de `src/interface`, de `src/application`, de d'une plateforme, ou touche le navigateur hors de ses deux implémentations du système de fichiers, qu'aucun autre de ses modules n'importe ; que `src/csv`, qui lit le modèle du stockage, importe de `src/application`, de `src/interface` -ou d'une plateforme ; et que `src/application` importe de `src/interface` ou de -Svelte. Un type que la documentation d'un module importe compte comme un -import. Le projet `node` ne chargeant pas le greffon Svelte (§ 14.8), un test de +ou d'une plateforme ; que `src/geometrie` importe en outre du moteur, de +`src/csv` ou de `src/demo` ; que `src/application` importe de `src/interface` ou +de Svelte ; et que `src/interface` importe autre chose que Svelte, ses propres +modules, `src/application` et `src/geometrie` — elle atteint le CSV et le moteur +par l'application, jamais en direct. Un type que la documentation d'un module +importe compte comme un import. Le projet `node` ne chargeant pas le greffon Svelte (§ 14.8), un test de moteur qui importerait un composant échoue au chargement — mais cette garde-là ne couvre que les composants, et un module qui touche `document` ne tomberait qu'à l'exécution de la branche fautive. @@ -3042,7 +3138,7 @@ suivante ; une règle qui fait échouer la construction tient. | niveau | ce qu'il couvre | quand | |---|---|---| -| **`node`, série surveillée** | moteur, géométrie, CSV, indicateurs et plafonds — des fonctions pures ; cohérence des versions (§ 18.5) ; appariement captures/manifeste (§ 19.7) ; aller-retour et canonicité du stockage sur la petite démonstration ; **une** production de planche de badges avec contrôle de géométrie et de couche de texte ; grille de propriétés sur petites instances | **à chaque modification**, quelques secondes (§ 14.14) | +| **`node`, série surveillée** | moteur, géométrie, CSV, indicateurs et plafonds — des fonctions pures ; l'application et les modules purs de l'interface, sur le système de fichiers simulé et l'horloge pilotée ; cohérence des versions (§ 18.5) ; appariement captures/manifeste (§ 19.7) ; aller-retour et canonicité du stockage sur la petite démonstration ; **une** production de planche de badges avec contrôle de géométrie et de couche de texte ; grille de propriétés sur petites instances | **à chaque modification**, quelques secondes (§ 14.14) | | **`node:long`** | accord de l'incrémental à 1, 10, 100, 1 000 et 10 000 mouvements ; rejeu du générateur et empreinte ; pagination des badges sur ses cinq comptes A4, ses quatre comptes Lettre et ses deux impositions ; reconstruction de tous les instants du journal ; aller-retour sur la grande démonstration ; coût d'enregistrement ; sonde d'écriture sur système de fichiers réel ; grande grille de propriétés | avant un commit, et à la construction | | **navigateur** | ce que l'interface dessine, ce que les gestes produisent, les coordonnées ; le scénario de pilotage (§ 19.3) ; le banc de mesure (§ 19.10) ; les épreuves de style calculé | avant chaque livraison | | **manuel** | une soirée complète, de la saisie à l'impression ; le décalage des imprimantes (§ 11.3) ; `pointercancel` et `touch-action` (§ 7.3) | avant chaque livraison au client | @@ -3093,18 +3189,30 @@ chaîne venue de la table de traduction d'une chaîne écrite dans le composant les deux s'affichent à l'identique. Les deux gardes sont un **balayage des sources** sous `node`, qui refuse une chaîne visible en dur et **échoue sur un balayage vide** (§ 14.2), et une **exécution en langue témoin** où chaque chaîne -traduite est décorée d'une marque : tout ce qui apparaît à l'écran sans sa marque -est écrit en dur. +traduite est encadrée d'une marque — `⁅` et `⁆`, U+2045 et U+2046, une fois, +autour du texte entier : tout ce qui apparaît à l'écran sans sa marque est écrit +en dur. La langue témoin est un mode du mécanisme, que la construction livrée +n'emploie jamais. + +**Un seul mécanisme, deux familles de tables.** Les textes de l'application — +codes de refus et d'avertissement, mise en forme des nombres et des durées — et +ceux des écrans vivent dans des tables distinctes, que réunit un seul mécanisme +de traduction. Un code s'affiche par sa propre clé, un libellé par une clé qui +nomme sa table ; une clé portée par deux tables, ou absente, lève — l'écran ne +montre jamais une clé brute ni un texte vide. Un texte qui devient une donnée — +le libellé figé d'une entrée du journal (§ 8.2), le motif du CSV des lignes +refusées (§ 10.1) — se compose en français, sans la marque de la langue témoin. ### 14.7 Le déterminisme Aucune source non reproductible — `Math.random`, `Date.now`, `performance.now`, -`crypto.getRandomValues` — dans le **moteur**, dans le **générateur de -démonstrations**, ni dans le **stockage** et l'**analyseur CSV**, qui reçoivent -l'horloge et l'aléa en paramètre. Un test de l'arborescence le refuse, **et -échoue si son balayage ne trouve aucun fichier**. Son périmètre est nommé : -`src/moteur`, `src/demo`, `src/stockage` et `src/csv`, à l'exclusion du code -d'épreuve, où un tirage sert légitimement (§ 14.12). L'interdit ne porte pas sur +`crypto.getRandomValues` — dans le **moteur**, dans la **géométrie du plan**, +dans le **générateur de démonstrations**, ni dans le **stockage** et +l'**analyseur CSV**, qui reçoivent l'horloge et l'aléa en paramètre. Un test de +l'arborescence le refuse, **et échoue si son balayage ne trouve aucun fichier**. +Son périmètre est nommé : `src/moteur`, `src/geometrie`, `src/demo`, +`src/stockage` et `src/csv`, à l'exclusion du code d'épreuve, où un tirage sert +légitimement (§ 14.12). L'interdit ne porte pas sur le reste de l'application : l'application lit l'horloge pour horodater les entrées de l'historique, que le stockage écrit telles qu'il les reçoit, et le banc de mesure du § 19.10 relève des temps par image. @@ -3127,8 +3235,8 @@ navigateur du § 14.4 sont deux configurations du même lanceur, pas deux outils | projet | environnement | ce qu'il inclut | greffon Svelte | |---|---|---|---| -| `node` | `node`, aucun DOM | `src/moteur`, `src/geometrie`, `src/stockage`, `src/csv`, `src/demo`, `src/pdf` | **absent** | -| `navigateur` | un vrai moteur de rendu, piloté par le mode navigateur de Vitest | `src/interface`, les épreuves de coordonnées et de style calculé | présent | +| `node` | `node`, aucun DOM | `src/moteur`, `src/geometrie`, `src/stockage`, `src/csv`, `src/demo`, `src/pdf`, `src/application`, et les modules purs de `src/interface` | **absent** | +| `navigateur` | un vrai moteur de rendu, piloté par le mode navigateur de Vitest | les composants de `src/interface`, les épreuves de coordonnées et de style calculé | présent | **Pourquoi Vitest.** Il lit la **configuration Vite qui construit le livrable** : un module importé par un test se résout exactement comme un module importé par l'application. Deux chaînes de résolution — l'une pour construire, @@ -3209,7 +3317,8 @@ donnée d'épreuve « pour un cas par défaut ». | analyseur CSV | `node` | encodage, séparateur, association des colonnes, réconciliation des appartenances, lignes refusées, aller-retour | | générateur de démonstrations | `node` | vecteur du générateur pseudo-aléatoire, empreinte des fichiers livrés, refus, noms forgés | | PDF | `node` | couche de texte, pagination, police embarquée et table `ToUnicode`, géométrie de la planche, reproductibilité | -| interface | navigateur | ce que les gestes produisent, le style calculé, les trois invariants du § 7.2 | +| application | `node` | les commandes et leurs refus, la séance observable, les contrôles de pose et de capacité, la table d'évaluation — sur le système de fichiers simulé et l'horloge pilotée | +| interface | navigateur ; ses modules purs sous `node` | ce que les gestes produisent, le style calculé, les trois invariants du § 7.2 | #### Le moteur @@ -3279,7 +3388,7 @@ style. **Au niveau navigateur**, la fonction pure est confrontée à `getScreenCTM().inverse()` sur un rendu réel, à plusieurs `k` et après défilement -de la page. **Les trois invariants du § 7.2 ont chacun leur test** : que le `` +de la page, à un millième de pixel d'écran près (§ 7.2). **Les trois invariants du § 7.2 ont chacun leur test** : que le `` racine ne porte pas d'attribut `viewBox` ; que son style calculé donne une bordure et un remplissage intérieur nuls — `getBoundingClientRect` les inclut, donc l'origine du contenu s'en décale ; qu'aucun ancêtre, ni lui-même, ne porte de @@ -4045,7 +4154,9 @@ valeur soit fixée ; un seul reste entièrement ouvert. les 33 tables avec listes. Aucune capture d'écran ne le mesure — une image est muette sur la durée qui l'a produite. Ce qui reste à dire est ce qu'est un temps par image **acceptable sur la machine de l'opérateur**, qui n'est pas celle du - développement. + développement. Sa valeur de travail a déjà une conséquence visible : sur un + écran de 1 366 × 700, la grande démonstration s'ajuste sous elle et s'ouvre + sans listes de noms, qui se dessinent en rapprochant la vue (§ 7.7). 7. **OUVERT, et hors périmètre de la première itération — les dégagements de référence d'une salle.** Le mot « conforme » reste absent de l'interface et la mention « disposition relative » reste sur chaque impression du plan (§ 7.7). @@ -4321,7 +4432,7 @@ question. Le logiciel fait donc en sorte qu'on n'ait pas à la chercher. | endroit | forme | |---|---| | **bandeau d'application**, sur tout écran (§ 8.4) | `2026.10.05.01`, avec la provenance et — quand un plan est ouvert — le libellé de mode | -| **premier écran** (§ 8.1), liste des événements comme répertoire vide | `version 2026.10.05.01` | +| **premier écran** (§ 8.1), liste des événements comme répertoire vide | `version 2026.10.05.01`, ou la marque de provenance d'une construction de documentation | | **titre de la fenêtre** | `Gestion table tournante Libre — 2026.10.05.01` | | **panneau « À propos »** | un bloc d'une ligne que l'opérateur **copie** | | **pied de chaque page imprimée** (§ 11.7) | la version, à côté de l'horodatage du placement | @@ -4345,7 +4456,7 @@ moment où l'opérateur peut encore se ménager un retour en arrière, c'est-à- avant le premier geste. **Le bloc copiable** du panneau « À propos » tient en une ligne — version affichée, -version technique, plateforme, provenance de la construction, version de format +version Windows, plateforme, provenance de la construction, version de format des fichiers — et se colle dans un courriel. Un chiffre recopié à la main se recopie faux. Il porte les **deux** formes parce qu'un opérateur qui lit la fiche de propriétés du fichier sous Windows y trouve `2026.1005.1.0` et non @@ -4364,8 +4475,8 @@ correctif et non du bruit à chaque geste. Il **n'est pas** la version de format qui reste un nombre séparé, comparé selon ses propres règles. **Pendant une construction de documentation, le numéro est remplacé par une marque -de provenance** — dans le bandeau, au pied des pages imprimées et sur la feuille de -contrôle des badges. La raison est au § 19.4 : sans cette marque, le texte relevé +de provenance** — dans le bandeau, sur le premier écran, au pied des pages +imprimées et sur la feuille de contrôle des badges. La raison est au § 19.4 : sans cette marque, le texte relevé de chaque capture d'écran change à chaque incrément de version, et toutes les images se réécrivent. Le manifeste, lui, enregistre la **version réelle**, et le contrôle de version de la livraison la compare (§ 19.7). @@ -4439,8 +4550,10 @@ ne les offre de façon portable : - **L'émulation d'une préférence système.** Le logiciel règle son **propre** réglage de thème, qui est celui que l'opérateur manipule (§ 13.3), et injecte une feuille de style qui annule transitions et animations. La préférence système - n'est consultée qu'au premier lancement, que le profil neuf du § 19.4 produit à - chaque exécution : **le scénario la pose explicitement et ne la déduit jamais.** + est consultée à chaque lancement, et le réglage de l'opérateur vaut pour la + séance : rien ne l'enregistre, ni fichier ni stockage du navigateur (§ 8.6). + **Le scénario pose donc le thème par le réglage, à chaque exécution, et ne le + déduit jamais de la machine.** ### 19.3 Le parcours, et ce qu'il photographie @@ -4548,7 +4661,7 @@ neutralise chaque source de variation nommément. | **le cadrage mémorisé** | le § 8.5 range le cadrage dans un fichier de réglages locaux : le scénario démarre sur un **profil neuf**, ce qui lui donne du même geste un dossier de travail neuf | | **le numéro d'ordre du nom de démonstration** | charger une démonstration crée « ‹nom› 2 » à la deuxième exécution (§ 15) ; le répertoire neuf ramène chaque exécution au premier ordinal | | **l'horloge** — horodatage d'historique, pied de page, « dernière modification », retour automatique en lecture | **une seule source d'horloge dans toute l'application hors moteur**, et **elle possède aussi les minuteries**. Un instant figé ne suffit pas : un compte à rebours bâti sur une minuterie du moteur d'exécution continue d'avancer sous une horloge gelée, et **le retour automatique en lecture tombe au milieu d'une étape**. Le scénario installe une horloge dont il contrôle l'avance, ce qui lui permet aussi d'éprouver les durées | -| **le numéro de version affiché** | une construction de documentation pose une **marque de provenance à la place du numéro** (§ 18.6), dans le bandeau comme au pied des pages imprimées et sur la feuille de contrôle des badges. Sans elle, le texte relevé de chaque capture change à chaque livraison, l'empreinte d'étape change avec lui, et **toutes les images se réécrivent à chaque incrément** — précisément le bruit que la réécriture conditionnelle du § 19.5 existe pour supprimer | +| **le numéro de version affiché** | une construction de documentation pose une **marque de provenance à la place du numéro** (§ 18.6), dans le bandeau, sur le premier écran, au pied des pages imprimées et sur la feuille de contrôle des badges. Sans elle, le texte relevé de chaque capture change à chaque livraison, l'empreinte d'étape change avec lui, et **toutes les images se réécrivent à chaque incrément** — précisément le bruit que la réécriture conditionnelle du § 19.5 existe pour supprimer | | **le chemin affiché** dans la liste des événements (§ 8.1) | racine de travail neutre, et le contrôle **refuse une capture dont le texte relevé — celui de tous les nœuds de texte de la région photographiée, pas des seuls éléments que l'étape nomme — porte un chemin hors de cette racine**. Un chemin réel porte un nom de compte, qu'une documentation publie | | **la police réellement rendue** | la police embarquée (§ 11.1) est celle du pilotage. Le scénario **mesure une chaîne témoin** par `getComputedTextLength()` et la compare à la valeur enregistrée **avec une tolérance relative, constante mesurée** (§ 14.1) — exiger l'égalité exacte reproduirait, sur une mesure de texte, l'erreur que cette section refuse sur les pixels. La tolérance se fixe au-dessous de l'écart qu'introduit un repli de police, qui est d'un tout autre ordre | | **le thème** | réglé par le réglage de l'application, non par une préférence système émulée (§ 19.2) |