Every gesture the pointer offers on the plan is reachable from the
keyboard (§ 7.3): one stop enters the plan, arrows move between tables and
seats, and the table and place panels choose a seat and keep the focus.
A tooltip names who sits where; a per-person menu moves, assigns or
reserves without dragging; the reserve and the work lists choose a person
to designate on the plan. Escape, a tour change and the executed command
forget the choice, and a click never moves the view.
Checked: 2537 node, 466 browser (one expected failure kept), 60 node-long.
--- FR ---
[ADD] interface : clavier du plan, infobulle, panneaux, menu, listes
Chaque geste que le pointeur offre sur le plan s'atteint au clavier
(§ 7.3) : un seul arrêt entre dans le plan, les flèches vont de table en
table et de siège en siège, et les panneaux de table et de place
choisissent un siège en gardant le focus. Une infobulle nomme qui est
assis où ; un menu par personne déplace, assigne ou réserve sans glisser ;
la réserve et les listes de travail choisissent une personne à désigner
sur le plan. Échap, un changement de tour et la commande exécutée
oublient le choix, et un clic ne déplace jamais la vue.
Vérifié : 2537 node, 466 navigateur (un échec attendu gardé), 60 node-long.
Assisted-by: Claude Opus 5.5
The plan is where the operator changes the seating. A drag starts only
past a movement threshold, so a click is never a drag (§ 8.4), and Escape
cancels it; a person dropped on a chair is moved or swapped through the
places commands, a table is moved, and a handle resizes it after the
capacity check. A refusal appears on the place where the gesture ended.
A new gesture waits for the previous write, so a second drag never starts
from a stale plan, and nothing reads layout while a drag runs.
Checked: 2499 node and 436 browser tests.
--- FR ---
[ADD] interface : gestes du plan — glisser une personne, une table
Le plan est l'endroit où l'opérateur change le placement. Un glissement ne
commence qu'au-delà d'un seuil de mouvement — un clic n'en est jamais un
(§ 8.4) — et Échap l'annule ; une personne déposée sur une chaise est
déplacée ou échangée par les commandes des places, une table se déplace,
et une poignée la redimensionne après le contrôle de capacité. Un refus se
pose sur la place où le geste a fini. Un geste attend l'écriture du
précédent, si bien qu'un second glissement ne part jamais d'un plan
périmé, et rien ne lit la mise en page pendant un glissement.
Vérifié : 2499 node et 436 navigateur.
Assisted-by: Claude Opus 5.5
Before generating, the operator must know what no plan can avoid: the
encounters a table size forces, the conflicts when every table holds
colleagues, the anchors that impose a return. The engine's diagnosis is
turned into sentences with their figures and their remedies, shown in its
section and, compact, beside the plan, whose banner states the floors
when every table is in conflict (§ 7.5).
Checked: 2425 node and 413 browser tests.
--- FR ---
[ADD] interface : diagnostic — ce qu'une configuration rend inévitable
Avant de générer, l'opérateur doit savoir ce qu'aucun plan n'évite : les
rencontres qu'une taille de table impose, les conflits quand chaque table
réunit des collègues, les ancrages qui imposent un retour. Le diagnostic du
moteur devient des phrases, avec leurs chiffres et leurs remèdes, montrées
dans sa section et, en compact, à côté du plan, dont le bandeau énonce les
planchers quand toutes les tables sont en conflit (§ 7.5).
Vérifié : 2425 node et 413 navigateur.
Assisted-by: Claude Opus 5.5
The operator chooses among the generated plans. The ranked table orders
propositions by the criteria of § 5.4 and shows, for encounters, the
minimum only — the mean is the same for every proposition at full tables
— with redundancy read through its sum. A proposition is retained or the
list cleared through named commands; clearing spares the retained one,
and a proposition that broke is shown apart, not ranked.
Checked: 2400 node and 406 browser tests.
--- FR ---
[ADD] interface : propositions — tableau classé, retenir, effacer
L'opérateur choisit parmi les plans générés. Le tableau classé ordonne les
propositions selon les critères du § 5.4 et ne montre, pour les
rencontres, que le minimum — la moyenne est la même pour toute
proposition à tables pleines —, la redondance se lisant par sa somme. Une
proposition se retient, ou la liste s'efface, par des commandes nommées ;
effacer épargne la retenue, et une proposition abîmée se montre à part,
hors classement.
Vérifié : 2400 node et 406 navigateur.
Assisted-by: Claude Opus 5.5
The operator launches a generation without the window freezing. The
screen sets the number of propositions, the seed, the stop count and the
history, refuses an out-of-range setting where it was typed, and asks
before a run estimated far beyond the default. The search runs in a worker
that terminate() cancels with no partial result, and the progress shows a
count, never a promised duration. The last duration lives for the session
only.
Checked: 2374 node and 391 browser tests.
--- FR ---
[ADD] interface : écran de génération — réglages, avancement, annulation
L'opérateur lance une génération sans figer la fenêtre. L'écran règle le
nombre de propositions, la graine, l'arrêt et l'historique, refuse un
réglage hors de son domaine là où il a été saisi, et demande avant un
calcul estimé bien au-delà du défaut. La recherche tourne dans un
travailleur que terminate() annule sans résultat partiel, et l'avancement
montre un compte, jamais une durée promise. La dernière durée ne vit que
le temps de la séance.
Vérifié : 2374 node et 391 navigateur.
Assisted-by: Claude Opus 5.5
The drawing becomes a plan the operator can look around. One transform on
the drawing group holds the view, so the screen and the drawing share the
formula of src/geometrie; the wheel zooms about the pointer without
scrolling the page, « + », « − » and « Ajuster » bound the scale, and a
resize keeps the view inside its limits. Only a deliberate gesture saves
the framing, deferred, into reglages_locaux.json — in read mode and on a
blocked plan too. The side panels take their first form.
Checked: 2368 node and 378 browser tests.
--- FR ---
[ADD] interface : vue du plan — zoom, cadrage, ajuster, échelle
Le dessin devient un plan que l'opérateur parcourt. Une seule
transformation du groupe de dessin tient la vue : l'écran et le dessin
partagent la formule de src/geometrie ; la molette zoome autour du
pointeur sans faire défiler la page, « + », « − » et « Ajuster » bornent
l'échelle, et un redimensionnement garde la vue dans ses limites. Seul un
geste voulu enregistre le cadrage, en différé, dans reglages_locaux.json
— en lecture et sur un plan bloqué aussi. Les panneaux latéraux prennent
leur première forme.
Vérifié : 2368 node et 378 navigateur.
Assisted-by: Claude Opus 5.5
The working screens of an evening. The home screen lists the events of
the working folder, asks its question, loads demos, copies, renames,
imports and deletes, and shows what the trash holds. An open event frames
its mode, offers Modifier, Débloquer and a confirmed lock takeover, and
shows its warnings. Participants get a grid, a form and a file; an import
goes through a preview and a report; tables, the default and tours have
their screens; the plan draws tables, chairs, empty seats and names.
Checked: 2342 node, 356 browser, 60 node-long; the Electron start check.
--- FR ---
[ADD] interface : liste, événement, participants, import, tables, plan
Les écrans de travail d'une soirée. L'accueil liste les événements du
dossier de travail, pose sa question, charge les démonstrations, copie,
renomme, importe et supprime, et montre ce que tient la corbeille. Un
événement ouvert encadre son mode, offre Modifier, Débloquer et une
reprise de verrou confirmée, et montre ses avertissements. Les
participants ont une grille, un formulaire et une fiche ; un import passe
par un aperçu et un rapport ; tables, défaut et tours ont leurs écrans ;
le plan dessine tables, chaises, sièges vides et noms.
Vérifié : 2342 node, 356 navigateur, 60 node-long ; démarrage d'Electron.
Assisted-by: Claude Opus 5.5
The window showed only a banner; it now holds the application. App mounts
the session, the facade and the generation, settles the working folder
and lists its events before it reports ready, re-reading the list once a
question is answered or a refused determination succeeds. The banner
carries version, mode and the event list command; an open event shows its
sections in their first form; the theme follows the system at each start
and the operator's choice lasts the session; À propos names the build.
Errors are collected for a report, and Electron removes the session's
locks at exit.
Checked: 2189 node, 193 browser, 60 node-long; the Electron start check.
--- FR ---
[ADD] interface : coquille — bandeau, sections, thème, À propos
La fenêtre ne montrait qu'un bandeau ; elle tient désormais l'application.
App monte la séance, la façade et la génération, règle le dossier de
travail et liste ses événements avant de se dire prête, et relit la liste
une fois une question répondue ou une détermination refusée réussie. Le
bandeau porte version, mode et la commande de la liste ; un événement
ouvert montre ses sections dans leur première forme ; le thème suit le
système à chaque démarrage et le choix de l'opérateur vaut pour la séance ;
À propos nomme la construction. Les erreurs se collectent pour un
signalement, et Electron efface à la sortie les verrous de la séance.
Vérifié : 2189 node, 193 navigateur, 60 node-long ; démarrage d'Electron.
Assisted-by: Claude Opus 5.5
Every screen of the plan edits, refuses and confirms the same way, so
these behaviours live once. A field validates on leaving it and shows a
refused value as refused, restoring the stored one when a session refusal
clears. A refusal is shown where the gesture happened, with its remedy as
an executable command. The confirmation window only opens for a gesture
that destroys data, and stays busy — no key closes it — until the
confirmed action ends.
Checked: 2152 node and 163 browser tests.
--- FR ---
[ADD] interface : primitives — champ, refus, confirmation, commande
Chaque écran du plan saisit, refuse et confirme de la même façon : ces
comportements n'existent qu'une fois. Un champ se valide à sa sortie et
montre une valeur refusée comme refusée, rendant la valeur enregistrée
quand un refus de séance s'efface. Un refus se pose là où le geste a eu
lieu, son remède en commande exécutable. La fenêtre à confirmer ne s'ouvre
que pour un geste qui détruit des données, et reste occupée — aucune touche
ne la ferme — jusqu'à la fin de l'action confirmée.
Vérifié : 2152 node et 163 navigateur.
Assisted-by: Claude Opus 5.5
Generating must never block the screen or record a plan that breaks a
rule. The controller refuses before launching, in a fixed order: an
out-of-range setting named by the engine's own check, the session's
refusals, then what makes the run useless. It runs the search in a worker
or in the thread, records only propositions whose invariants hold, skips
plans already present, and keeps the last duration for the session only.
The evaluation table ranks propositions on the minimum of encounters and
names the reservations a proposition does not honour.
Checked: 2112 node and 60 node-long tests; coverage floors kept.
--- FR ---
[ADD] application : génération, travailleur, table d'évaluation
Générer ne doit jamais bloquer l'écran ni enregistrer un plan qui enfreint
une règle. Le contrôleur refuse avant tout lancement, dans un ordre fixe :
un réglage hors de son domaine, nommé par la règle même du moteur, les
refus de la séance, puis ce qui rend le calcul vain. Il lance la recherche
dans un travailleur ou dans le fil, n'enregistre que les propositions dont
les invariants tiennent, écarte les plans déjà présents, et garde la
dernière durée pour la seule séance. La table d'évaluation classe les
propositions sur le minimum de rencontres et nomme les réservations
qu'une proposition ne tient pas.
Vérifié : 2112 node et 60 node-long ; seuils de couverture tenus.
Assisted-by: Claude Opus 5.5
Changing a table, the default seat count or the number of tours reshapes
a plan the operator may already have retained. Eight commands create,
remove and resize tables and set the default and the tours; every change
of capacity first passes controlerCapacite, which refuses to cut a reserved
or titled seat, states who goes to the reserve, and only brings back a
reserved person the display showed seated (§ 6.1, § 6.2). bilans.js states
the figures of a change before it applies.
Checked: 2033 node and 127 browser tests.
--- FR ---
[ADD] application : mobilier — tables, défaut, tours, contrôles
Changer une table, le défaut de sièges ou le nombre de tours remodèle un
plan que l'opérateur a peut-être retenu. Huit commandes créent, retirent et
redimensionnent les tables, et règlent le défaut et les tours ; tout
changement de capacité passe d'abord par controlerCapacite, qui refuse de
couper un siège réservé ou titré, dit qui part en réserve, et ne ramène une
personne réservée que si l'écran la montrait assise (§ 6.1, § 6.2).
bilans.js énonce les chiffres d'un changement avant qu'il s'applique.
Vérifié : 2033 node et 127 navigateur.
Assisted-by: Claude Opus 5.5
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
The interface tests must judge what an operator sees, not what the markup
claims: a class can sit on an element that paints nothing (§ 14.2).
test/navigateur/ gives them shared helpers: entering the app as a user
does, reading the colour actually painted under a text — the topmost
opaque background below it, an outer <svg> background included — and
deciding visibility by geometry, style and occlusion rather than by
hit-testing, so overlays in pointer-events: none stay visible. The header
names what the helpers do not detect.
Checked: 1776 node and 127 browser tests.
--- FR ---
[ADD] épreuves : outillage du navigateur — entrées, couleurs, contraste
Les épreuves de l'interface doivent juger ce que voit l'opérateur, non ce
que prétend le balisage : une classe peut se poser sur un élément qui ne
peint rien (§ 14.2). test/navigateur/ leur donne des aides communes :
entrer dans l'application comme un utilisateur, lire la couleur réellement
peinte sous un texte — le premier fond opaque sous lui, celui d'un <svg>
extérieur compris — et juger la visibilité par la géométrie, le style et
l'occultation plutôt que par l'atteinte du pointeur. L'en-tête nomme ce
que les aides ne détectent pas.
Vérifié : 1776 node et 127 navigateur.
Assisted-by: Claude Opus 5.5
Under a non-UTF-8 locale, Chromium returns the parent folder for an
accented folder name without raising, so a write meant for that folder
replaced a file of the same name in its parent. Each step of a path walk
now compares the handle with its parent and refuses NOM_NON_CONVERTI —
LECTURE on reads, ECRITURE on writes — and nothing lands elsewhere. The
test launcher gives Chromium LANG=C.UTF-8 when the locale is not UTF-8, as
the containers do, and the matrix installs ps where an image lacks it.
Checked: 1776 node and 45 browser tests; the guard holds under LC_ALL=C.
--- FR ---
[FIX] stockage web : refuser un nom non converti, lancement en UTF-8
Hors locale UTF-8, Chromium rend le dossier parent pour un nom de dossier
accentué, sans lever : une écriture destinée à ce dossier remplaçait un
fichier homonyme de son parent. Chaque pas d'un chemin compare désormais le
dossier obtenu à son parent et refuse NOM_NON_CONVERTI — LECTURE en lecture,
ECRITURE en écriture — : rien n'atterrit ailleurs. Le lanceur des épreuves
donne LANG=C.UTF-8 à Chromium quand la locale n'est pas UTF-8, comme les
conteneurs, et la matrice installe ps là où une image en manque.
Vérifié : 1776 node, 45 navigateur ; la garde tient sous LC_ALL=C.
Assisted-by: Claude Opus 5.5
The screens need one clock, one translation mechanism and one way to
format and name, or each component grows its own. horloge.js is the only
code that reads time and arms timers, injected so tests drive it.
traduction.js keys texts by domain, in two families of tables, raises on a
missing key and never shows a raw key; libelles/ splits the label table by
domain. format.js formats numbers and dates in French, and personnes.js
composes the displayed name the frozen labels use. Nothing persists
between sessions.
Checked: 1773 node and 43 browser tests.
--- FR ---
[ADD] application : horloge, traduction, mise en forme, nom affiché
Les écrans exigent une horloge, un mécanisme de traduction et une façon de
mettre en forme et de nommer, sans quoi chaque composant ferait les siens.
horloge.js est le seul code qui lit l'heure et arme des minuteries, injecté
pour que les épreuves le pilotent. traduction.js range les textes par
domaine, en deux familles de tables, lève sur une clé absente et ne montre
jamais une clé brute ; libelles/ découpe la table des libellés par domaine.
format.js met en forme nombres et dates en français, et personnes.js
compose le nom affiché qu'emploient les libellés figés. Rien ne persiste
d'une séance à l'autre.
Vérifié : 1773 node et 43 navigateur.
Assisted-by: Claude Opus 5.5
The plan's colours carry meaning — a conflict, a reservation, a mode — so
they must stay readable for every reader and in both themes. jetons.css
defines the tokens for the light and dark themes, set by data-theme on the
root; palette.js reads them from the stylesheet text and checks, by
computation, contrast to WCAG and separation under the three
dichromacies, keeping the conflict hue reserved. The theme follows the
system at each start and the operator's choice lasts the session.
Checked: 1709 node and 43 browser tests.
--- FR ---
[ADD] interface : jetons de couleur, deux thèmes, palette, marques
Les couleurs du plan portent un sens — un conflit, une réservation, un mode
— et doivent rester lisibles pour tout lecteur et dans les deux thèmes.
jetons.css définit les jetons des thèmes clair et sombre, posés par
data-theme sur la racine ; palette.js les lit dans le texte de la feuille
et contrôle, par calcul, le contraste au sens des WCAG et la séparation
sous les trois dichromaties, la teinte du conflit restant réservée. Le
thème suit le système à chaque démarrage ; le choix de l'opérateur vaut
pour la séance.
Vérifié : 1709 node et 43 navigateur.
Assisted-by: Claude Opus 5.5
A table's tabletop, chairs, footprint and handle derive from its number of
places, chairs numbered clockwise from the top, in drawing centimetres.
The seat a pointer designates is read from the same chairs the drawing
places, through one implementation, so what is drawn and where a drop
lands cannot disagree. No table rotates.
Checked: 1681 node tests.
--- FR ---
[ADD] géométrie : les tables, leurs chaises, la désignation d'un siège
Le plateau, les chaises, l'emprise et la poignée d'une table dérivent de son
nombre de places, chaises numérotées depuis le haut dans le sens horaire,
en centimètres de dessin. Le siège que désigne un pointeur se lit sur les
chaises mêmes que le dessin pose, par une seule implémentation : ce qui est
dessiné et l'endroit où tombe un dépôt ne peuvent diverger. Aucune table ne
tourne.
Vérifié : 1681 épreuves node.
Assisted-by: Claude Opus 5.5
The plan needs one formula between the screen and the drawing, shared by
the drawing, the seat designation and the drop of a drag. src/geometrie/vue
holds the view as k px/cm plus a translation, written in a single
transform attribute, and converts pointer positions without reading the
DOM. Text truncation, the graphic scale and the register of measured
constants live beside it; the layer guard now requires src/geometrie and
keeps it deterministic and away from window.
Checked: 1619 node tests.
--- FR ---
[ADD] géométrie : vue du plan, troncature, échelle, constantes mesurées
Le plan exige une seule formule entre l'écran et le dessin, que partagent le
dessin, la désignation d'un siège et le dépôt d'un glissement.
src/geometrie/vue tient la vue — k px/cm et une translation — écrite dans un
seul attribut transform, et convertit les positions du pointeur sans lire
le DOM. La troncature du texte, l'échelle graphique et le registre des
constantes mesurées vivent à côté ; la garde des couches exige désormais
src/geometrie, déterministe et sans window.
Vérifié : 1619 épreuves node.
Assisted-by: Claude Opus 5.5
The plan view must say at which table and round a conflict sits, and the
quality page must aggregate diversity. indicateurs.js now exports the single
pass that reads a plan round by round and table by table, from which
mesurer draws every figure; conflits.js gives its detail per table, so the
totals and the table view share one arithmetic (§ 13.2). The diagnosis
gains its repartition, remedies, single-affiliation flag and the anchors
that force a return.
Checked: 1582 node and 60 node-long tests; indicateurs.js at 100 %.
--- FR ---
[ADD] moteur : conflits par table, diversité agrégée, diagnostic enrichi
La vue du plan doit dire à quelle table et à quel tour se trouve un
conflit, et la page de qualité agréger la diversité. indicateurs.js exporte
le seul passage qui lit un plan tour par tour et table par table, d'où
mesurer tire chaque chiffre ; conflits.js en rend le détail par table : les
totaux et la vue par table partagent une arithmétique (§ 13.2). Le
diagnostic gagne sa répartition, ses remèdes, le drapeau d'appartenance
unique et les ancrages qui imposent un retour.
Vérifié : 1582 node et 60 node-long ; indicateurs.js à 100 %.
Assisted-by: Claude Opus 5.5
The operator plans, the room is not tracked live: removing a person from
the retained plan must free her chair and leave every other seat where it
is. With seats assigned, a table list may now hold null before its last
occupant, seat 1 included, and never end on it; without assignment no
list holds null. Validation, canonical form, patches and the named form
handle it, and the delivered demos keep their bytes.
Checked: 1549 node and 58 node-long tests; depot.js, journal.js at 100 %.
--- FR ---
[ADD] stockage : chaise vide dans une liste de table aux sièges attribués
L'opérateur planifie, la salle ne se suit pas en direct : retirer une
personne du plan retenu doit libérer sa chaise et laisser tout autre siège
à sa place. Sièges attribués, une liste de table peut porter null avant son
dernier occupant, siège 1 compris, jamais à la fin ; sans attribution,
aucune liste ne porte null. Contrôle, forme canonique, correctifs et forme
nommée le traitent, et les démonstrations livrées gardent leurs octets.
Vérifié : 1549 node et 58 node-long ; depot.js, journal.js à 100 %.
Assisted-by: Claude Opus 5.5
On Linux, Chromium converts origin-private file names through the process
locale. The debian:13 and fedora:44 images set no LANG, so every accented
name failed with TypeMismatchError there, while Arch, which sets C.UTF-8,
passed. The container steps now run under LANG=C.UTF-8, and a browser test
names that cause when a Chromium cannot write an accented name. The long
test that reads the real ps skips with its reason when ps is missing.
Checked: debian-13 and fedora-44 test_navigateur and test_long green in
containers; 36 browser and 26 node-long tests locally.
--- FR ---
[FIX] matrice : locale UTF-8 pour Chromium, lecture ps sautée sans ps
Sous Linux, Chromium convertit les noms de fichiers de l'origine privée par
la locale du processus. Les images debian:13 et fedora:44 ne posent aucun
LANG : chaque nom accentué y échouait (TypeMismatchError), alors qu'Arch,
qui pose C.UTF-8, passait. Les étapes des conteneurs tournent sous
LANG=C.UTF-8, et une épreuve du navigateur nomme cette cause quand un
Chromium n'écrit pas un nom accentué. L'épreuve longue qui lit le vrai ps se
saute, raison dite, quand ps manque.
Vérifié : debian-13 et fedora-44 au vert en conteneur ; 36 + 26 en local.
Assisted-by: Claude Opus 5.5
A lock judged by its pid alone took a reused pid for a live session after a
reboot, and the event stayed locked. The lock now records the process start
time; a session is dead only when that is certain — no process with the pid,
or two known start times that differ — and alive only when they match.
Otherwise liveness is unknown and the session is not taken over, so two
sessions never write at once (§ 8.8). The pause-and-retry on EPERM, EBUSY
and EACCES that guarded only the rename now guards appends, moves and
deletes too, through one helper.
Checked: 1538 node, 26 node-long tests; the macOS start time is read in UTC.
--- FR ---
[FIX] electron : vie du verrou sûre, réessais sur chaque écriture
Un verrou jugé sur son seul pid prenait un pid réattribué pour une séance
vivante après un redémarrage, et l'événement restait verrouillé. Le verrou
inscrit désormais l'heure de démarrage du processus ; une séance n'est morte
que si c'est certain — aucun processus de ce pid, ou deux heures connues qui
diffèrent — et vivante que si elles concordent. Sinon sa vie est inconnue
et la séance n'est pas reprise : deux séances n'écrivent jamais ensemble
(§ 8.8). La pause et les réessais sur EPERM, EBUSY et EACCES, qui ne
gardaient que le renommage, gardent aussi ajouts, déplacements et
suppressions, par une seule aide.
Vérifié : 1538 node, 26 node-long ; l'heure de démarrage macOS se lit en UTC.
Assisted-by: Claude Opus 5.5
An update file without a prénom or appartenance column matched nobody who
had one, and added everyone again. Prénom and appartenance now narrow the
match only when both the line and the participant carry them. A quote that
opened a field and closed anywhere later swallowed records and could merge
two people; a closing quote not followed by a separator or a record end now
refuses the file with GUILLEMET_OUVERT. The preview takes the import mode,
so in replace mode no line is shown as a duplicate of someone deleted.
Checked: 1519 node tests, the new cases red on the previous code.
--- FR ---
[FIX] csv : rapprochement, guillemet égaré, aperçu selon le mode
Un fichier de mise à jour sans colonne prénom ou appartenance ne retrouvait
personne qui en avait une, et ajoutait tout le monde de nouveau. Prénom et
appartenance ne restreignent désormais le rapprochement que s'ils sont des
deux côtés. Un guillemet qui ouvrait un champ et se fermait plus loin avalait
des lignes et pouvait fondre deux personnes ; un guillemet fermant que ne
suit ni séparateur ni fin d'enregistrement refuse le fichier (GUILLEMET_OUVERT).
L'aperçu prend le mode : en remplacement, aucune ligne n'est un doublon d'une
personne supprimée.
Vérifié : 1519 épreuves node ; les nouveaux cas, rouges sur l'ancien code.
Assisted-by: Claude Opus 5.5
The whole-iteration review found ways to lose or corrupt data. A state
saved in another encoding opened with its accents turned to U+FFFD and was
then overwritten; decoding is now strict, the state opens read-only, and a
gesture from its secours first moves it to the trash. A journal decodes line
by line, so one bad byte drops only the lines after it. A vanished journal
is rewritten whole, never appended to. Deleting refuses an event another
session holds; switching to writing rereads the disk; an import that
changes exclu says which reservations it suspends.
Checked: 1504 node, 35 browser, 29 node-long; depot.js, journal.js 100 %.
--- FR ---
[FIX] stockage, séance : UTF-8 strict, journal perdu, verrou, exclusions
La revue d'ensemble a trouvé des façons de perdre ou d'abîmer des données.
Un état enregistré dans un autre encodage s'ouvrait, ses accents changés en
U+FFFD, puis s'écrasait ; le décodage est strict, l'état s'ouvre en lecture
seule, et un geste depuis son secours le range d'abord à la corbeille. Le
journal se décode ligne par ligne : un octet fautif n'écarte que la suite.
Un journal disparu se réécrit en entier, jamais par ajout. Supprimer refuse
un événement qu'une autre séance tient ; passer en écriture relit le disque ;
un import qui change exclu dit quelles réservations il suspend.
Vérifié : 1504 node, 35 navigateur, 29 node-long ; depot.js, journal.js 100 %.
Assisted-by: Claude Opus 5.5
One node test walks § 2.1 through the session on the simulated disk:
create, switch to writing, import the edge-case CSV as one entry, correct
two people, generate with the engine, retain, exclude a person, reopen with
the dérive named and the retained plan kept, undo before the generation,
reopen. Every instant of the journal rebuilds the state written at that
moment, no opening writes, and undo keeps the id counters (§ 8.9).
Checked: 1424 node tests; five mutations of the real code each caught.
--- FR ---
[ADD] application : épreuve de bout en bout du parcours de l'opérateur
Une épreuve node parcourt le § 2.1 par la séance, sur le disque simulé :
créer, passer en écriture, importer le CSV des cas limites en une entrée,
corriger deux personnes, générer avec le moteur, retenir, exclure une
personne, rouvrir — dérive nommée, retenu gardé —, défaire jusqu'avant la
génération, rouvrir. Chaque instant du journal reconstruit l'état écrit à
ce moment, aucune ouverture n'écrit, et défaire garde les compteurs (§ 8.9).
Vérifié : 1424 épreuves node ; cinq mutations du code réel, chacune prise.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
Undoing back before a generation restored the whole charge, its
prochainsIds included: the next generation numbered its propositions 1 to 3
again, and a label of the abandoned thread such as "retained proposition 2"
named another proposition. § 8.9 forbids it: a counter never goes back. A
retour now restores the content of the instant and keeps each counter at
the larger of its restored and current value, so the next id is fresh.
Checked: 1416 node tests; the retour test is red on the previous seance.js.
--- FR ---
[FIX] séance : un retour ne fait jamais reculer les compteurs
Défaire jusqu'avant une génération restituait la charge entière, prochainsIds
compris : la génération suivante renumérotait ses propositions de 1 à 3, et
un libellé du fil abandonné, comme « retenu la proposition 2 », désignait
une autre proposition. Le § 8.9 l'interdit : un compteur ne recule jamais.
Un retour restitue désormais le contenu de l'instant et porte chaque
compteur au plus grand de sa valeur restituée et de sa valeur courante.
Vérifié : 1416 épreuves node ; l'épreuve du retour est rouge sur l'ancien code.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
npm 11 runs no install script it has not been told about and warns at each
install. electron-winstaller only builds Squirrel installers for Windows;
the Windows target here is the portable executable, so its script (picking
a 7-Zip binary) is never needed. Denying it in allowScripts records that
choice and silences the warning on ./run.sh and ./install_dev.sh.
Checked: npm install-scripts ls reports nothing unreviewed; 353 tests.
--- FR ---
[UPD] construction : refuser nommément le script d'electron-winstaller
npm 11 ne lance aucun script d'installation qu'on ne lui a pas nommé et le
signale à chaque installation. electron-winstaller ne sert qu'aux
installateurs Squirrel de Windows ; la cible Windows est ici l'exécutable
portable, et son script (le choix d'un 7-Zip) n'y sert jamais. Le refuser
dans allowScripts inscrit ce choix et tait l'avertissement de ./run.sh.
Vérifié : npm install-scripts ls ne signale plus rien ; 353 épreuves.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
The session holds one event, opens it read-only and writes only after
"Modifier" takes the lock (§ 8.4, § 8.8); calls run one after another, so a
double click writes two entries in order. Every change is a pure named
command with a frozen French label (§ 8.2); undo, redo and return write
entries and never truncate the journal (§ 8.3). A failed write — a gesture,
or the lock on a removed key — breaks the medium until the event is written
elsewhere (§ 8.6). The label table covers every code storage, CSV and the
session emit, and its test sweeps the sources so a new code needs a text.
Checked: 1416 node tests; depot.js at 100 % with the identifier lister keeps.
--- FR ---
[ADD] application : séance, commandes nommées, table des libellés
La séance tient un événement, l'ouvre en lecture et n'écrit qu'après que
« Modifier » a pris le verrou (§ 8.4, § 8.8) ; les appels passent l'un après
l'autre : un double clic écrit deux entrées, dans l'ordre. Toute modification
est une commande nommée pure au libellé français figé (§ 8.2) ; défaire,
refaire et revenir écrivent des entrées sans tronquer le journal (§ 8.3). Une
écriture refusée — un geste, ou le verrou sur une clé retirée — rompt le
support jusqu'à l'écriture ailleurs (§ 8.6). La table des libellés couvre
chaque code du stockage, du CSV et de la séance ; son épreuve balaie les
sources, et un code neuf exige un texte.
Vérifié : 1416 épreuves node ; depot.js à 100 %, lister gardant l'identifiant.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
§ 8.7 operations reuse the event store's pairing and alignment instead of
copying them. Renaming writes the complete pair under the new name — the
store now writes a gesture with the pair it writes elsewhere — before
deleting the old one, so no cut leaves zero pairs; an unchanged name writes
nothing. Deleting moves state, .precedent, journal, lock and leftovers into a
dated trash, matching names as the case-insensitive disk does. creerDossier
creates only the root it is aimed at, so a vanished working folder never
comes back empty. reglages_locaux.json keeps exactly the two § 8.5 settings;
its deferred writer always keeps the last demand.
Checked: 1314 node, 35 browser, 27 node-long tests; depot.js at 100 %.
--- FR ---
[ADD] stockage : copier, renommer, importer, supprimer ; réglages locaux
Les opérations du § 8.7 reprennent l'appariement et l'alignement du dépôt au
lieu de les recopier. Renommer écrit la paire complète sous le nouveau nom —
le dépôt écrit désormais un geste avec la paire qu'il pose ailleurs — avant
de supprimer l'ancienne : aucune coupure ne laisse zéro paire ; un nom
inchangé n'écrit rien. Supprimer range état, .precedent, journal, verrou et
restes dans une corbeille datée, en comparant les noms comme le disque
insensible à la casse. creerDossier ne crée que la racine visée : un dossier
de travail disparu ne renaît pas vide. reglages_locaux.json garde les deux
réglages du § 8.5 ; son écrivain différé garde la dernière demande.
Vérifié : 1314 node, 35 navigateur, 27 node-long ; depot.js à 100 %.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
§ 8.2 makes the cost of a full save a measured threshold, since every
gesture rewrites the whole state file. The node-long test times a swap in
the retained plan of the big demo with twenty propositions — journal line,
.precedent, state, on the real file system — and the gesture that prunes
the journal past 600 entries. It keeps sampling while the minimum stays
above the threshold, within a bounded window, so a burst of load passes and
a uniform regression fails. Each gesture's files and every revision are
checked, so a save that skips a file cannot lower the measure.
Checked: 3 node-long tests; red under a ×5 slowdown of every gesture.
--- FR ---
[ADD] stockage : coût mesuré d'un enregistrement complet, grande démo
Le § 8.2 fait du coût d'un enregistrement complet un seuil mesuré, puisque
chaque geste réécrit tout le fichier d'état. L'épreuve node-long chronomètre
un échange dans le plan retenu de la grande démonstration à vingt
propositions — ligne de journal, .precedent, état, sur le vrai système de
fichiers — et le geste qui élague le journal au-delà de 600 entrées. Elle
mesure encore tant que le minimum dépasse le seuil, dans une fenêtre bornée :
une rafale de charge passe, une régression uniforme échoue. Les fichiers de
chaque geste et chaque révision sont vérifiés.
Vérifié : 3 épreuves node-long ; rouge sous un ralentissement ×5.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
The spec said less than the code enforces, so a reader could not tell a rule
from an accident. It now states: ten minutes of inactivity before read mode
(§ 8.4); reglages_locaux.json (§ 8.5); the probe that creates the chosen
working folder, the temporary Chromium profile, and the name bound on the
longest path an event writes, trash and atomic write included (§ 8.6); the
proposition counter and per-proposition seat flag (§ 8.9); the closed list of
exclu values, encoding refusals and the one-column file (§ 10.1); the layer
and determinism guards, the coverage floors, and the workstation (§ 13, § 16).
Checked: 1266 node tests on the result.
--- FR ---
[UPD] spec : stockage, CSV et poste de développement selon le code
Le spec en disait moins que le code n'en impose : un lecteur ne distinguait
pas une règle d'un hasard. Il énonce désormais : dix minutes d'inactivité
avant la lecture (§ 8.4) ; reglages_locaux.json (§ 8.5) ; la sonde qui crée le
dossier de travail retenu, le profil temporaire de Chromium et la borne posée
sur le plus long chemin écrit, corbeille et écriture atomique comprises
(§ 8.6) ; le compteur des propositions et le drapeau des sièges (§ 8.9) ; la
liste fermée d'exclu, les refus d'encodage, le fichier à une colonne
(§ 10.1) ; les gardes des couches et du déterminisme, les seuils de
couverture et le poste de développement (§ 13, § 16).
Vérifié : 1266 épreuves node sur le résultat.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
make couverture runs the node series under V8 instrumentation and prints one
row per module, full ones included, plus a line-by-line HTML report. Four
modules hold a hard 100 % branch floor — indicateurs.js, plafond.js,
depot.js, journal.js — and the command fails below it; there is no global
threshold, which covering the easy modules would satisfy. The tree guard
refuses a lowered or global floor, a floor on a file the measure never loads,
and a command that does not measure. It extends determinism and layer
boundaries to src/stockage, src/csv and src/application (§ 13.4), and no
longer takes a string literal for DOM access.
Checked: 1266 node tests; the four floors at 100 %.
--- FR ---
[ADD] épreuves : couverture par module, seuils durs, gardes des couches
make couverture joue la série node sous l'instrumentation de V8 et imprime une
ligne par module, pleins compris, et un rapport HTML ligne à ligne. Quatre
modules tiennent un seuil dur de 100 % des branches — indicateurs.js,
plafond.js, depot.js, journal.js — et la commande échoue en deçà ; aucun seuil
global, qu'on satisferait en couvrant les modules faciles. La garde de
l'arborescence refuse un seuil abaissé ou global, un seuil sur un fichier que
la mesure ne charge pas, et une commande qui ne mesure pas. Elle étend le
déterminisme et les frontières des couches à src/stockage, src/csv et
src/application (§ 13.4), et ne prend plus une chaîne littérale pour le DOM.
Vérifié : 1266 épreuves node ; les quatre seuils à 100 %.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
An event is a state file and a journal paired by its internal identifier,
never by name (§ 8.6): a hand copy of a state does not take the original's
journal, and a renamed journal stays paired. Each gesture writes its journal
line first, then the .precedent and the state (§ 8.2); recovery compares
revisions, never file dates, so a cut leaves the journal one entry ahead at
most. Opening never writes (§ 8.4); an unreadable state names its readable
secours instead of opening an empty event, and a newer format stays
read-only. Writing elsewhere after a removed medium aligns the pair first.
Checked: 60 tests, 100 % branches of depot.js, 1257 node tests on HEAD.
--- FR ---
[ADD] stockage : dépôt d'événements — lister, créer, ouvrir, reprendre
Un événement est un fichier d'état et un journal appariés par l'identifiant
interne, jamais par le nom (§ 8.6) : un état copié à la main ne prend pas le
journal de l'original, et un journal renommé reste apparié. Chaque geste
écrit sa ligne de journal d'abord, puis le .precedent et l'état (§ 8.2) ; la
reprise compare les révisions, jamais la date des fichiers : une coupure
laisse le journal en avance d'une entrée au plus. Ouvrir n'écrit jamais
(§ 8.4) ; un état illisible nomme ses secours lisibles au lieu d'ouvrir un
événement vide, et un format plus récent reste en lecture seule. Écrire
ailleurs après un support retiré aligne d'abord la paire.
Vérifié : 60 épreuves, 100 % des branches de depot.js, 1257 épreuves node.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
Without seat attribution a table list stays sorted, so swapping two
people shifted every rank between them and a patch grew to over a
kilobyte; a same-length list of ids is now set whole when that is
lighter, and a swap costs two small operations (§ 8.9). A patch that
sets a malformed proposition or retained placement is refused at its
rank, instead of a TypeError at the next application. Identifiers stay
below 2^31, the engine's Int32Array bound: beyond, the record is a
form fault, and a proposition is set aside.
Checked: storage tests; reviewed, remaining findings minor.
--- FR ---
[FIX] stockage : correctifs compacts, poses contrôlées, id sous 2^31
Sans attribution des sièges, une liste de table reste triée : échanger
deux personnes décalait chaque rang entre elles, et un correctif passait
le kilo-octet ; une liste d'identifiants de même longueur se pose
désormais entière quand c'est plus léger, et un échange coûte deux
petites opérations (§ 8.9). Un correctif qui pose une proposition ou un
retenu mal formé est refusé à son rang, au lieu d'une TypeError à
l'application suivante. Les identifiants restent sous 2^31, borne des
Int32Array du moteur : au-delà, faute de forme, et proposition écartée.
Vérifié : épreuves du stockage ; revue, constats restants mineurs.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
The shell carries the file-system boundary (§ 13.1): the page names a
root the main process defines — data/ beside the published executable,
the product folder in Documents, or one the operator picks in a dialog —
and a relative path, refused if absolute, with .., a NUL, or a real
path outside the root. Writes go to a temporary file, flushed, renamed
over the target with retries; a failed rename never truncates it. The
lock records session, process and host. Chromium's profile lives in a
temporary folder removed at exit, not in AppData nor in the events.
Checked: node and real-folder long tests; real Electron start under Ozone.
--- FR ---
[ADD] electron : système de fichiers confiné, écriture atomique, verrou
La coquille porte la frontière du système de fichiers (§ 13.1) : la page
nomme une racine que le processus principal définit — data/ à côté de
l'exécutable publié, le dossier du produit dans Documents, ou un dossier
choisi par dialogue — et un chemin relatif, refusé s'il est absolu, porte
.., un NUL, ou un chemin réel hors de la racine. Une écriture passe par
un temporaire vidé sur le disque puis renommé par-dessus, réessayé ; un
renommage manqué ne tronque jamais la cible. Le profil de Chromium vit
dans un dossier temporaire effacé à la sortie, hors d'AppData.
Vérifié : épreuves node et longues sur dossier réel ; Electron réel lancé.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
Under the web platform, used to develop and test on Linux, events live
in the browser's origin private file system: one root, with no
executable folder, no atomic rename and no lock, which it declares so
the start-up banner can say so (§ 8.8). Imports come through a file
input and exports through a download link. The same contract suite as
the test double runs on it in Chromium, its exclusivity check skipped
because there is no lock to test.
Checked: the contract suite in the browser project; one review round.
--- FR ---
[ADD] stockage : système de fichiers web, sur le stockage de l'origine
Sous la plateforme web, qui sert au développement et aux épreuves sous
Linux, les événements vivent dans le stockage privé de l'origine du
navigateur : une seule racine, sans dossier d'exécutable, sans renommage
atomique ni verrou, ce qu'il déclare pour que le bandeau de démarrage le
dise (§ 8.8). Les imports passent par un champ de fichier, les exports
par un lien de téléchargement. La suite de contrat du double s'y joue
dans Chromium, sauf l'exclusivité, faute de verrou à éprouver.
Vérifié : la suite de contrat sous le projet navigateur ; une revue.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
The four demonstrations ship as event files written once by a script,
the source of truth of § 15.5: a test replays the generator and compares
SHA-256 fingerprints of the payload alone, naming the paths that differ,
so a new build version never forces a regeneration. The affiliation
profile is read from the delivered file. The two demonstration CSVs are
the export of those files; the edge-case CSV is written by hand, and
its windows-1252 variant derived. Version and forged-name guards skip
these generated files, as § 18.5 and § 15.6 allow.
Checked: node and long series; the script writes only its seven files.
--- FR ---
[ADD] démo : fichiers d'événement livrés, CSV d'exemple, empreinte
Les quatre démonstrations se livrent en fichiers d'événement qu'un
script écrit une fois, source de vérité du § 15.5 : une épreuve rejoue
le générateur et compare les empreintes SHA-256 de la seule charge, en
nommant les chemins qui diffèrent ; une nouvelle version n'impose donc
aucune régénération. Le profil d'appartenances se lit dans le fichier
livré. Les deux CSV de démonstration sont l'export de ces fichiers ;
celui des cas limites s'écrit à la main, sa variante windows-1252 en
dérive. Les gardes de version et de noms forgés passent ces fichiers.
Vérifié : séries node et longue ; le script n'écrit que ses sept fichiers.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
An import applies its preview by adding, updating or replacing.
Updating designates one participant by name, first name and, when
given, affiliation; an empty field keeps the stored value, and a row
that designates several is refused. Replacing first counts what it
destroys, reservations and filled titles included. A blocked plan
refuses; a retained one warns of drift. Refused rows come back as a CSV
of the original columns plus line and reason, which reimports as is;
the list exports in the exact form the import reads.
Checked: 59 tests, the round trip field by field and the refusal loop.
--- FR ---
[ADD] csv : import de trois façons, refus réexportés, liste exportée
Un import applique son aperçu en ajoutant, mettant à jour ou
remplaçant. La mise à jour désigne un participant par nom, prénom et,
s'il est donné, appartenance ; un champ vide garde la valeur, et une
ligne qui en désigne plusieurs est refusée. Remplacer compte d'abord ce
qu'il détruit, réservations et titres pourvus compris. Un plan bloqué
refuse ; un plan retenu avertit de la dérive. Les lignes refusées
reviennent en CSV des colonnes d'origine, plus ligne et motif, qui se
réimporte tel quel ; la liste s'exporte dans la forme que l'import lit.
Vérifié : 59 épreuves, l'aller-retour champ par champ et la boucle.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
Once per session the rule picks where events live (§ 8.6): data/ next
to the executable that the portable launcher publishes, unless that
folder sits under per-user application data or a temporary folder, or
a written witness does not read back; Documents otherwise, with the
reason. A data/ that holds events but refuses writes raises a question
instead of a silent switch; an empty folder with events elsewhere
proposes their import. A removable medium and the web platform are
announced. It writes only the probes' witnesses.
Checked: 20 tests, the five outcomes on the failing double; branches 100%.
--- FR ---
[ADD] stockage : dossier de travail, data/ portable ou Documents
Une fois par séance, la règle choisit où vivent les événements (§ 8.6) :
data/ à côté de l'exécutable que publie le lanceur portable, sauf sous
des données applicatives ou un dossier temporaire, ou quand un témoin
écrit ne se relit pas ; sinon Documents, raison dite. Un data/ qui porte
des événements mais refuse l'écriture pose une question au lieu d'une
bascule muette ; un dossier vide alors que l'autre en porte propose leur
import. Un support amovible et la plateforme web s'annoncent. Elle
n'écrit que les témoins des sondes.
Vérifié : 20 épreuves, les cinq issues sur le double ; branches 100 %.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
The journal is one JSON line per entry, after a line that pairs it with
its event by id. An entry carries its frozen label, a display timestamp,
and either a snapshot or a patch from the line before; a snapshot every
fifty revisions keeps any instant within 49 applications. Reading stops
at the first unreadable line and counts what it drops. Returns never
truncate: undo, redo and jumps are entries, and the current thread is
told from abandoned ones. Past 600 entries it prunes on a snapshot
boundary, never below 500.
Checked: unit tests, and every instant rebuilt over long sequences.
--- FR ---
[ADD] stockage : journal en ajout, instantané tous les cinquante, fils
Le journal est une ligne JSON par entrée, après une ligne qui l'apparie
à son événement par identifiant. Une entrée porte son libellé figé, un
horodatage d'affichage, et soit un instantané, soit un correctif depuis
la ligne précédente ; un instantané toutes les cinquante révisions tient
tout instant à 49 applications. La lecture s'arrête à la première ligne
illisible et compte ce qu'elle écarte. Revenir ne tronque jamais :
défaire, refaire et sauter sont des entrées, et le fil courant se
distingue des fils abandonnés. Au-delà de 600 entrées, élagage sur une
frontière d'instantané, jamais sous 500.
Vérifié : épreuves unitaires ; tous les instants reconstruits.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
Columns associate by header, never by position, insensitive to case,
accents and spaces, with the § 10.1 synonyms; two columns for one field
associate neither and ask. The preview imports nothing: it lists valid
rows, refused rows with their reason, each group of merged spellings
with its counts, duplicates never merged, and global refusals, an open
quote or a NUL included. A paste goes through the same parser, and the
separator rule lives once, in lecture.js, whose refusal names its line.
Checked: 185 CSV tests, eight spreadsheet-shaped fixtures; two reviews.
--- FR ---
[ADD] csv : colonnes par en-tête, valeurs d'exclu fermées, aperçu
Les colonnes s'associent par en-tête, jamais par position, sans égard à
la casse, aux accents ni aux espaces, avec les synonymes du § 10.1 ;
deux colonnes d'un même champ ne s'associent pas, et le logiciel
demande. L'aperçu n'importe rien : lignes valides, lignes refusées et
leur motif, chaque groupe d'orthographes fondues et ses comptes,
doublons jamais fondus, refus globaux, guillemet ouvert et nul compris.
Le collage passe par le même analyseur, et la règle du séparateur ne
s'écrit qu'une fois, dans lecture.js, dont le refus nomme sa ligne.
Vérifié : 185 épreuves CSV, huit données de tableur ; deux revues.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
Storage code receives its file system as a parameter (§ 13.4): one
interface, and here the implementation tests inject. It keeps files in
memory, shares a disk between two instances to replay a restart, and
fails on demand: a refused rename that leaves the target intact, writes
refused from a moment on, a process killed after n writes, a failing
probe, a removable medium. One contract suite, its assertions passed in,
will run unchanged on the Electron and web implementations.
Checked: 87 tests, the contract suite run on the test double.
--- FR ---
[ADD] stockage : interface du système de fichiers, double, contrat
Le code du stockage reçoit son système de fichiers en paramètre
(§ 13.4) : une interface, et ici l'implémentation que les épreuves
injectent. Elle garde les fichiers en mémoire, partage un disque entre
deux instances pour rejouer un redémarrage, et tombe en panne à la
demande : renommage refusé qui laisse la cible intacte, écritures
refusées à partir d'un instant, processus tué après n écritures, sonde
qui échoue, support amovible. Une suite de contrat, ses assertions
reçues en paramètre, servira telle quelle sous Electron et sous web.
Vérifié : 87 épreuves, la suite de contrat jouée sur le double.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
The journal stores a gesture as a patch from the previous payload, not
a full copy. Records with an id are compared by id, so adding a person
does not shift the others; same-length lists compare element by
element; other values are set whole. Moving one person in one round of
a large plan touches two seat lists. Applying never alters its input
and refuses a patch that does not fit, naming the operation.
Checked: 25 tests including a property over generated payloads.
--- FR ---
[ADD] stockage : correctifs entre deux charges, par identifiant
Le journal range un geste comme un correctif depuis la charge
précédente, non comme une copie entière. Les enregistrements à
identifiant se comparent par identifiant, si bien qu'ajouter une
personne ne décale pas les autres ; les listes de même longueur se
comparent élément par élément ; le reste se pose en entier. Déplacer une
personne à un tour d'un grand plan touche deux listes de sièges.
Appliquer ne modifie jamais son entrée et refuse un correctif qui ne
s'applique pas, en nommant l'opération.
Vérifié : 25 épreuves, dont une propriété sur des charges tirées.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
Placements are stored positionally: per proposition its seed, stop
count, history length and building version, then per round the ordered
tables and the reserve. A proposition that contradicts itself — wrong
length, repeated, unknown or missing id, an id already taken — is named
and left out, and the event still opens. One that no longer matches the
event — person excluded or added, table removed, capacity or rounds
changed — is kept and reported as drift. A named form serves reading.
Checked: 42 tests on the small demonstration; reviewed, mutants killed.
--- FR ---
[ADD] stockage : placements positionnels, fautes et dérives
Les placements se rangent par position : pour chaque proposition sa
graine, son compte d'arrêt, la longueur d'historique et la version qui
l'a produite, puis par tour les tables ordonnées et la réserve. Une
proposition qui se contredit — longueur fausse, identifiant répété,
inconnu, manquant ou déjà pris — est nommée et écartée, et l'événement
s'ouvre. Celle qui ne décrit plus l'événement — personne exclue ou
ajoutée, table retirée, capacité ou tours changés — est gardée et
signalée comme dérive. Une forme nommée sert à la lecture.
Vérifié : 42 épreuves sur la petite démonstration ; revue, mutants tués.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
A file name derives from the event name: invisible code points and
characters Windows refuses removed, NFC before and after, a reserved
device name suffixed even before a dot, a collision compared in capitals
as Windows compares. The bound covers the longest path an event writes,
dated trash folder and atomic-write suffix included, under 259 units; a
name that leaves nothing becomes « evenement ». The trash rank stops at
the 99 the bound reserves.
Checked: 91 tests on both working folders, mutants killed, fuzzed names.
--- FR ---
[ADD] stockage : noms de fichiers admis par Windows, chemins bornés
Le nom de fichier dérive du nom de l'événement : points de code
invisibles et caractères que Windows refuse retirés, NFC avant et après,
nom de périphérique réservé suffixé même devant un point, collision
comparée en capitales comme Windows compare. La borne couvre le plus long
chemin qu'un événement écrit, corbeille datée et suffixe d'écriture
atomique compris, sous 259 unités ; un nom qui ne laisse rien devient
« evenement ». Le rang de corbeille s'arrête aux 99 que la borne réserve.
Vérifié : 91 épreuves sur les deux dossiers, mutants tués, noms tirés.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
An event lives in one state file: a header (format, writing build,
revision, counts) and a payload. The serializer orders keys by one
schema table and records by id, sorts the sets — reserves, placed
participants, unattributed seats — and reads no clock nor randomness:
one state gives one text, byte for byte. Reading refuses an empty,
truncated or self-contradicting file by reason and path, reads a newer
format with its unknown keys ignored, never refuses a whole file for
one proposition. The engine exports its default history length.
Checked: 58 tests and the golden text; two reviews, mutants killed.
--- FR ---
[ADD] stockage : document d'événement, forme canonique, contrôle
Un événement vit dans un fichier d'état : un en-tête (format,
construction qui écrit, révision, comptes) et une charge. Le sérialiseur
range les clés par une seule table de schéma et les enregistrements par
identifiant, trie les ensembles — réserves, participants placés, sièges
non attribués — et ne lit ni horloge ni aléa : un état, un texte, octet
pour octet. La lecture refuse un fichier vide, tronqué ou contradictoire
par raison et chemin, lit un format plus récent en ignorant ses clés
inconnues, et ne refuse jamais un fichier pour une proposition.
Vérifié : 58 épreuves et le texte exact ; deux revues, mutants tués.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
Bytes decode in the order of § 10.1: UTF-8 mark, UTF-16 mark, a NUL in
the first 4 KiB without a mark refused with its remedy, then strict
UTF-8, then windows-1252. A mark its bytes contradict, and any decoded
NUL, are refused: decoded, they would give names no later check sees.
The separator is the candidate among ";", "," and tab that leaves no
quote open and gives one field count above one on the first twenty
records; a lone recognised header reads as one column. Records follow
RFC 4180 and are numbered as a spreadsheet numbers its rows.
Checked: 89 tests, 60 mutants killed; review found no behaviour defect.
--- FR ---
[ADD] csv : décodage en quatre temps, choix du séparateur, découpage
Les octets se décodent dans l'ordre du § 10.1 : marque UTF-8, marque
UTF-16, octet nul dans les 4 Kio sans marque refusé avec son remède,
UTF-8 strict, puis windows-1252. Une marque contredite par ses octets,
et tout nul décodé, sont refusés : décodés, ils donneraient des noms
qu'aucun contrôle ne verrait. Le séparateur parmi « ; », « , » et la
tabulation ne laisse aucun guillemet ouvert et donne un même nombre de
champs, plus d'un, sur vingt enregistrements ; un en-tête seul reconnu
se lit en une colonne. Découpage RFC 4180, rangs comme dans un tableur.
Vérifié : 89 épreuves, 60 mutants tués ; aucun défaut à la revue.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
make with no target does what ./run.sh does: Electron on a graphical
session, Vite's server without one or where Electron is not published
(s390x, ppc64le). Every npm, npx and node recipe goes through the
project's Node. make essai_demarrage starts the real Electron through
Playwright and reads its window title, on Chromium's headless Ozone
platform when there is no display: no X server is needed.
scripts/verifier_systemes.sh replays install and tests in podman over
the QEMU catalogue of TODO, and stops only its own containers.
Checked: 17 Linux images and Nix pass all six steps; pwsh parses.
--- FR ---
[ADD] lancement : make et ./run.sh, essai d'Electron, matrice
make sans cible fait ce que fait ./run.sh : Electron sur une session
graphique, le serveur de Vite sans elle ou là où Electron n'est pas
publié (s390x, ppc64le). Chaque recette npm, npx ou node passe par le
Node du projet. make essai_demarrage lance la vraie coquille Electron
par Playwright et lit le titre de sa fenêtre, sur la plateforme Ozone
headless de Chromium sans écran : aucun serveur X n'est requis.
scripts/verifier_systemes.sh rejoue installation et épreuves sous
podman sur le catalogue QEMU de TODO, et n'arrête que ses conteneurs.
Vérifié : 17 images Linux et Nix passent les six étapes ; pwsh analyse.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
./install.sh installs what is missing through apt, dnf, zypper or
pacman, then Node of the .node-version major from nodejs.org, SHA-256
checked, outside the repository, then npm ci and Electron's binary,
which its package no longer fetches at install; ldd refuses a missing
library. ./install_dev.sh adds Playwright's Chromium, fonts, and podman
on amd64. Under NixOS a pinned shell.nix provides Node, Electron and
Chromium, which the browser tests then launch. Build-script tests run
on Linux only, where § 16 builds.
Checked: ten library tests, three mutations caught; local install.
--- FR ---
[ADD] installation : Node 26 et paquets du système, par famille et Nix
./install.sh installe ce qui manque par apt, dnf, zypper ou pacman, puis
Node de la majeure de .node-version, de nodejs.org, somme SHA-256
vérifiée, hors du dépôt, puis npm ci et le binaire d'Electron, que son
paquet ne télécharge plus à l'installation ; ldd refuse une bibliothèque
absente. ./install_dev.sh ajoute le Chromium de Playwright, des polices,
et podman sur amd64. Sous NixOS, un shell.nix épinglé fournit Node,
Electron et Chromium, que lancent alors les épreuves du navigateur. Les
épreuves du script de construction ne se jouent que sous Linux (§ 16).
Vérifié : dix épreuves de la bibliothèque, trois mutations attrapées ;
installation locale.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
install.cmd, install_dev.cmd and run.cmd hand over to PowerShell
scripts that place Node of the .node-version major under %LOCALAPPDATA%,
checked against the SHA-256 that nodejs.org publishes, then run npm ci:
no administrator right is needed. The scripts stay within Windows
PowerShell 5.1, shipped with Windows, and carry a UTF-8 byte order mark,
without which 5.1 reads them in the system code page and mangles
accents. The licence guard now reads .ps1, .cmd, .nix and Makefile.
Checked: parsed and run under pwsh in a container, Node for win-x64
downloaded, verified and extracted; not yet run on Windows itself.
--- FR ---
[ADD] scripts : installer et lancer sous Windows, par PowerShell 5.1
install.cmd, install_dev.cmd et run.cmd passent la main à des scripts
PowerShell qui posent Node de la majeure de .node-version sous
%LOCALAPPDATA%, vérifié contre la somme SHA-256 que publie nodejs.org,
puis lancent npm ci : aucun droit d'administrateur n'est requis. Les
scripts s'en tiennent à Windows PowerShell 5.1, livré avec Windows, et
portent une marque d'ordre d'octets UTF-8, sans laquelle 5.1 les lit
dans la page de code du système et défigure les accents. La garde de
licence lit désormais les .ps1, .cmd, .nix et le Makefile.
Vérifié : analysés et exécutés sous pwsh en conteneur, Node win-x64
téléchargé, vérifié, extrait ; pas encore exécutés sous Windows même.
Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb