Commit graph

146 commits

Author SHA1 Message Date
62f8406d78 [ADD] print: welcome list and table sheets, paginated with headers
The welcome list sorts names by their normalised key and gives each
round a column whose width comes from the longest seat it holds; the
table sheet puts the rounds in columns, or one sheet per table and
round under « Une feuille par tour ». Rows are measured and paginated
with the header repeated, never split across pages; names wrap
instead of being cut. Read-only and locked plans print the same.
Checked: node 3753, browser 730, node-long 101 from the index alone.

--- FR ---

[ADD] impression : liste d'accueil et feuilles par table, paginées

La liste d'accueil trie les noms par leur clé normalisée et donne à
chaque tour une colonne large de la plus longue place qu'elle porte ;
la feuille par table met les tours en colonnes, ou une feuille par
table et par tour sous « Une feuille par tour ». Les lignes sont
mesurées et paginées sous l'en-tête répété, jamais coupées entre deux
pages ; les noms passent à la ligne plutôt que d'être tronqués. Un plan
en lecture ou verrouillé s'imprime de même.
Vérifié : node 3753, navigateur 730, node-long 101 depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-10 11:07:03 -04:00
e5d9026b2a [ADD] print: seating plan cut into pages, with cartouche and scale
The printed plan draws every table in seat mode with its name lists,
whatever the zoom, and drops screen gestures: no selection, focus,
grab handle or highlight reaches paper. Each page carries a cartouche
(page p of n, column, row) and references to its neighbours; the cut
uses the band measured under the footer. Print marks resolve their
colour tokens from the printed document, so a dark screen theme
leaves the paper light.
Checked: node 3721, browser 720, node-long 101 from the index alone.

--- FR ---

[ADD] impression : plan découpé en pages, avec cartouche et échelle

Le plan imprimé dessine chaque table en régime sièges, avec ses listes
de noms, quel que soit le zoom, et laisse les gestes à l'écran :
sélection, focus, poignée et mise en évidence n'atteignent pas le
papier. Chaque page porte un cartouche (page p sur n, colonne, rangée)
et ses renvois aux voisines ; la découpe prend la bande mesurée sous le
pied. Les marques lisent leurs jetons dans le document imprimé : un
thème sombre à l'écran laisse le papier clair.
Vérifié : node 3721, navigateur 720, node-long 101 depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-10 11:03:12 -04:00
1e5039af5b [ADD] audit: first engine mutation audit, survivors killed in tests
The audit must say how much of the engine its tests really check. Of 2576
mutants, 2171 are killed, 207 time out, 61 are declared equivalent with a
reason a reviewer can check, and 137 survive, listed by file, operator and
line; the ranking, indicators and ceiling modules have none left. New
tests in classement, indicateurs and plafond kill the survivors found
there, each red under its mutant.
Checked: 3677 node and 101 long tests green from the index alone.

--- FR ---

[ADD] audit : premier audit par mutation du moteur, survivants tués

L'audit doit dire combien du moteur ses épreuves vérifient vraiment. Sur
2576 mutants, 2171 sont tués, 207 dépassent leur délai, 61 sont déclarés
équivalents avec une raison qu'un relecteur vérifie, et 137 survivent,
listés par fichier, opérateur et ligne ; le classement, les indicateurs et
le plafond n'en ont plus. De nouvelles épreuves de classement, indicateurs
et plafond tuent les survivants trouvés là, chacune rouge sous son mutant.
Vérifié : 3677 node et 101 longues vertes depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-09 17:12:23 -04:00
416d91a88f [ADD] badges: prepare, produce and save the sheet from the session
The operator needs the badge sheet as a file next to the event, built
from what the session shows at that moment. The session prepares an
announcement (sheets per paper, counts, namesakes, missing glyphs, draft),
then produces the PDF through a single deferred import of the PDF code and
writes it atomically; under the web build it downloads instead. A gesture
started during production waits its turn. A proposal sheet is always a
draft, and an unwritable file or a missing paper choice gives its refusal
with a remedy.
Checked: red first; 3670 node, 707 browser and 101 long tests green from
the index alone.

--- FR ---

[ADD] badges : préparer, produire et déposer la planche depuis la séance

L'opérateur a besoin de la planche en fichier, à côté de l'événement, tirée
de ce que la séance montre à cet instant. La séance prépare une annonce
(planches par papier, comptes, homonymes, glyphes absents, brouillon), puis
produit le PDF par un seul import différé du code PDF et l'écrit de façon
atomique ; sous web, elle le télécharge. Un geste lancé pendant la
production attend son tour. Une planche tirée d'une proposition est
toujours un brouillon, et un fichier non écrit ou un papier non choisi
donnent leur refus avec un remède.
Vérifié : rouge d'abord ; 3670 node, 707 navigateur et 101 longues vertes
depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-09 17:11:48 -04:00
858018323b [ADD] print: preview screen, printable sheet, paper question
Printed pages must show exactly what will come out of the printer. An
Imprimer button in the event header opens a preview screen where each page
is a sheet at paper size, light whatever the theme, with its footer and,
under the strict draft rule, BROUILLON in outline; a proposal shown on a
retained plan prints as a draft. The paper is asked once per machine and
can be changed there. The table sheets offer one sheet per round. A failed
print shows IMPRESSION_ECHEC. The captures are republished with the button.
Checked: red first; 3651 node, 707 browser and 101 long tests green from
the index alone.

--- FR ---

[ADD] impression : aperçu, feuille imprimable, question du papier

Une page imprimée doit montrer exactement ce que l'imprimante rendra. Un
bouton Imprimer de la tête de l'événement ouvre un aperçu où chaque page
est une feuille au format du papier, claire quel que soit le thème, avec
son pied et, sous la règle stricte, BROUILLON au trait ; une proposition
montrée sur un plan retenu s'imprime en brouillon. Le papier se demande une
fois par machine et s'y change. Les feuilles par table offrent une feuille
par tour. Une impression échouée affiche IMPRESSION_ECHEC. Les captures
sont republiées avec le bouton.
Vérifié : rouge d'abord ; 3651 node, 707 navigateur et 101 longues vertes
depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-09 17:11:37 -04:00
43dbfad8a5 [ADD] docs: photographed walkthrough publishes doc/captures
The screenshots must come from the tested walkthrough, not from a separate
script that can drift. The browser walkthrough runs on the simulated file
system with a driven clock and the direct executor, light theme, 1366 x
700 at scale 1, transitions off, and photographs each step once its
condition holds. make captures writes the images and the manifest; the
plain test run compares them instead. Eighteen captures are published, the
later ones named as postponed. The forged-names scan skips the manifest,
which records the demo names shown on screen.
Checked: red first; 3620 node, 681 browser and 101 long tests green from
the index alone.

--- FR ---

[ADD] docs : parcours photographié, publication de doc/captures

Les captures doivent venir du parcours éprouvé, non d'un script à part qui
dérive. Le parcours navigateur joue sur le système de fichiers simulé,
l'horloge pilotée et l'exécuteur direct, thème clair, 1366 × 700 au facteur
1, transitions coupées, et photographie chaque étape quand sa condition
tient. make captures écrit les images et le manifeste ; la série ordinaire
les compare au lieu de les écrire. Dix-huit captures sont publiées, les
suivantes nommées reportées. Le balayage des noms forgés saute le
manifeste, qui relève les noms de démonstration affichés.
Vérifié : rouge d'abord ; 3620 node, 681 navigateur et 101 longues vertes
depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-09 15:33:59 -04:00
3e4fd03a4c [IMP] generation: duration estimate counts the slowdown of busy cores
A core runs slower when its neighbours work too, so the estimate that
divided the run by the number of workers promised too short a wait. The
estimate now multiplies by rho(W), linear from 1 on one core to the
registry constant RALENTISSEMENT_PLEINE_CHARGE when every logical
processor works; the cores setting itself is unchanged. A bench file
measures the curve. An out-of-range setting is refused before
AUCUN_EVENEMENT.
Checked: red first; 3582 node and 659 browser tests green from the index.

--- FR ---

[IMP] génération : l'estimation compte le ralentissement des cœurs

Un cœur va moins vite quand ses voisins travaillent aussi : l'estimation
qui divisait le calcul par le nombre de travailleurs promettait une attente
trop courte. Elle multiplie désormais par rho(W), linéaire de 1 sur un cœur
à la constante RALENTISSEMENT_PLEINE_CHARGE du registre quand tous les
processeurs logiques travaillent ; le réglage des cœurs ne change pas. Un
fichier du banc mesure la courbe. Un réglage hors domaine est refusé avant
AUCUN_EVENEMENT.
Vérifié : rouge d'abord ; 3582 node et 659 navigateur verts depuis l'index.

Assisted-by: Claude Opus 5.5
2026-10-09 15:28:49 -04:00
8fb80324e7 [ADD] pdf: badge sheet production with control page and draft mark
The badge sheet must print at true scale and read back exactly what the
model says. Page 1 is the control sheet: badge size, paper, counts,
namesakes, missing glyphs and a 100 mm ruler; it continues on extra control
pages when a long reprint overflows. One page per sheet follows, with cut
lines, embedded Noto Sans subsets and a ToUnicode map, no metadata, so the
same model yields the same bytes. A draft carries BROUILLON in outline on
every page; the word comes from the caller, never from src/pdf.
Checked: red first, text read back through pdfjs; 3541 node and 101 long
tests green from the index alone.

--- FR ---

[ADD] pdf : production de la planche, page de contrôle, brouillon

La planche de badges doit s'imprimer à l'échelle et se relire exactement
comme le modèle le dit. La page 1 est la feuille de contrôle : taille du
badge, papier, comptes, homonymes, glyphes absents et règle de 100 mm ; elle
continue sur des pages de contrôle quand une longue réédition déborde. Suit
une page par planche, avec traits de coupe, sous-ensembles de Noto Sans et
table ToUnicode, sans métadonnées : le même modèle rend les mêmes octets.
Un brouillon porte BROUILLON au trait sur chaque page ; le mot vient de
l'appelant, jamais de src/pdf.
Vérifié : rouge d'abord, texte relu par pdfjs ; 3541 node et 101 longues
vertes depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-09 15:26:53 -04:00
8b7c732399 [ADD] platform: print bridge, atomic byte writes, badge sheet file name
Printed views and the badge sheet leave the app through the platform. Under
Electron a gtt:imprimer channel prints with the paper and orientation asked
for and reports sent, cancelled, failed or unknown; an exception is logged
to the console and never shown raw to the operator. Every file system,
real or simulated, writes bytes atomically from a copy taken at the call.
The sheet name carries event, date and imposition, and a failed print
becomes IMPRESSION_ECHEC.
Checked: red first, twelve mutations caught; 3502 node, 659 browser and 79
long tests green from the index alone.

--- FR ---

[ADD] plateforme : pont d'impression, octets atomiques, nom de planche

Les vues imprimables et la planche sortent de l'application par la
plateforme. Sous Electron, un canal gtt:imprimer imprime au papier et à
l'orientation demandés et rend envoyé, annulé, échec ou inconnu ; une
exception va à la console, jamais brute à l'opérateur. Chaque système de
fichiers, réel ou simulé, écrit des octets de façon atomique, depuis une
copie prise à l'appel. Le nom de la planche porte événement, date et
imposition, et une impression échouée devient IMPRESSION_ECHEC.
Vérifié : rouge d'abord, douze mutations attrapées ; 3502 node, 659
navigateur et 79 longues vertes depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-09 15:26:13 -04:00
307ee526fc [ADD] bench: versioned record format and its agreement with constants
Measured thresholds must be adopted by a developer, never written by the
bench into the code. The record holds the bench configuration and its
measures; its reader refuses an empty record, a measure without its
constant, and any field or value that looks like a host, an account or a
date. A guard in the constants test makes every registry value that claims
a bench origin agree with the record.
Checked: red first, eight mutations caught; 3392 node tests green from the
index alone.

--- FR ---

[ADD] banc : format du relevé versionné, accord avec les constantes

Un seuil mesuré s'adopte par un geste du développeur ; le banc ne l'écrit
jamais dans le code. Le relevé porte la configuration du banc et ses
mesures ; sa lecture refuse un relevé vide, une mesure sans sa constante,
et tout champ ou valeur qui ressemble à un hôte, un compte ou une date. Une
garde de l'épreuve des constantes accorde au relevé chaque valeur du
registre qui se dit tirée du banc.
Vérifié : rouge d'abord, huit mutations attrapées ; 3392 node verts depuis
l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-09 13:03:20 -04:00
4e25e73a5d [ADD] badges: sheet model from the retained plan or a chosen proposal
Badges hang on guests' necks: their content must be exact and stable. The
model builds one badge per non-excluded person, from the retained plan or,
on demand, from a proposal, which always prints as a draft. Each round says
table, seat when seats are assigned, and a title only where a reservation
makes the person its holder there; a constant itinerary takes one line.
Names sort by code point, never by locale; namesakes carry their id, and a
reprint gives the same texts. Without any placement it refuses, pointing at
the proposals.
Checked: red first; 3343 node tests green from the index alone.

--- FR ---

[ADD] badges : modèle de planche, du retenu ou d'une proposition choisie

Les badges pendent au cou des invités : leur contenu doit être exact et
stable. Le modèle fait un badge par personne non exclue, depuis le retenu
ou, sur demande, une proposition, toujours imprimée en brouillon. Chaque
tour dit la table, le siège sous attribution, et un titre seulement là où
une réservation en fait la personne titulaire ; un itinéraire constant tient
en une ligne. Les noms se classent par points de code, jamais selon la
locale ; les homonymes portent leur identifiant, et une réédition rend les
mêmes textes. Sans aucun placement, il refuse et renvoie aux propositions.
Vérifié : rouge d'abord ; 3343 node verts depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-09 13:03:04 -04:00
270c27f7ed [ADD] pdf: badge layout with a sacrifice order and injected metrics
A badge must keep the name whole and readable whatever its length. The pure
layout picks the largest name size that fits in one to three lines, then
lays rounds on one or two columns down to the floor size, then drops the
event name from the footer and then the affiliation; past that it refuses.
A round line too wide shortens its title only, keeping at least one grapheme
of it, never the table or seat. Metrics are injected, so the same code lays
out under Noto Sans and under a fixed-pitch test font.
Checked: red first; 3299 node tests green from the index alone.

--- FR ---

[ADD] pdf : badge mis en page, ordre de sacrifice, métriques injectées

Un badge doit garder le nom entier et lisible, quelle que soit sa longueur.
La mise en page, pure, choisit le plus grand corps du nom qui tient en une à
trois lignes, pose les tours sur une ou deux colonnes jusqu'au corps
plancher, puis retire du pied le nom de l'événement, puis l'appartenance ;
au-delà, elle refuse. Une ligne de tour trop large n'abrège que son titre,
en garde au moins une grappe, jamais la table ni le siège. Les métriques
sont injectées : le même code se met en page sous Noto Sans et sous une
police d'épreuve à chasse fixe.
Vérifié : rouge d'abord ; 3299 node verts depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-09 13:02:53 -04:00
0ac686487f [ADD] geometry: cut the seating plan into printed pages
A plan too large to read on one sheet must print as a grid of pages that
join exactly. The cut picks the orientation that gives fewest pages, then
the larger scale, then landscape; tiles meet at exact equality on 2^-20 cm
coordinates, columns are lettered A to Z then AA, and a table or name block
that straddles two pages is reported on both. The print bounding box
includes measured name blocks but no handle or target.
Checked: red first, including a fast-check property on drawn plans, papers
and thresholds; 3245 node tests green from the index alone.

--- FR ---

[ADD] géométrie : découpe du plan de salle en pages imprimées

Un plan trop grand pour se lire sur une feuille doit s'imprimer en une
grille de pages qui se joignent exactement. La découpe choisit
l'orientation qui donne le moins de pages, puis la plus grande échelle, puis
le paysage ; les tuiles se touchent à l'égalité exacte sur des cotes de
2^-20 cm, les colonnes vont de A à Z puis AA, et une table ou un bloc de
noms à cheval sur deux pages se signale sur les deux. L'englobant imprimé
compte les blocs de noms mesurés, sans poignée ni cible.
Vérifié : rouge d'abord, dont une propriété fast-check sur plans, papiers
et seuils tirés ; 3245 node verts depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-09 13:02:18 -04:00
88d35f5979 [IMP] interface: Noto Sans everywhere, faces loaded before mounting
The screen must match the screenshots and the text the tests measure. The
interface now uses the embedded Noto Sans for every element, form controls
included, with a 1.3 line height. The entry point and the test mount wait
for both faces before mounting, so no text measurer caches the fallback
width; a face that fails to load is reported and the app mounts anyway.
The screens the wider font overflowed have their own CSS adjusted.
Checked: red first; 3216 node, 655 browser and 71 long tests green from the
index; the Electron start-up check loads the font from file://.

--- FR ---

[IMP] interface : Noto Sans partout, faces chargées avant le montage

L'écran doit ressembler aux captures et au texte que mesurent les épreuves.
L'interface emploie désormais Noto Sans, embarquée, pour tout élément,
contrôles de formulaire compris, avec un interligne de 1,3. Le point
d'entrée et le montage d'épreuve attendent les deux faces avant de monter :
aucun mesureur ne garde la largeur de repli ; une face qui ne se charge pas
est signalée et l'application se monte quand même. Les écrans que la police
plus large débordait ajustent leur propre CSS.
Vérifié : rouge d'abord ; 3216 node, 655 navigateur et 71 longues vertes
depuis l'index ; l'essai de démarrage charge la police par file://.

Assisted-by: Claude Opus 5.5
2026-10-09 13:01:49 -04:00
d8a6fb8202 [ADD] bench: a priori ceiling cost on the largest and worst events
Spec 17 point 4 asks whether the a priori ceiling is cheap enough to compute
on every check. The bench times plafondsAPriori and diagnostiquer on the
large demonstration, its variant without exceptions, and a pessimistic
event of 260 people, 33 tables of 8 and 10 rounds with every signature
distinct: about 0.075 ms, 0.04 ms and 11.5 ms. A long test guards each at
four times its reference, so losing the memoisation turns it red.
Checked: red first under that mutant; 3208 node and 71 long tests green.

--- FR ---

[ADD] banc : coût du plafond a priori, grand événement et pire cas

Le spec 17, point 4, demande si le plafond a priori se calcule assez vite
pour chaque contrôle. Le banc mesure plafondsAPriori et diagnostiquer sur
la grande démonstration, sa variante sans exception, et un événement
pessimiste de 260 personnes, 33 tables de 8 et 10 tours aux signatures
toutes distinctes : environ 0,075 ms, 0,04 ms et 11,5 ms. Une épreuve
longue garde chacun à quatre fois sa référence : perdre la mémoïsation la
rend rouge.
Vérifié : rouge d'abord sous ce mutant ; 3208 node et 71 longues vertes.

Assisted-by: Claude Opus 5.5
2026-10-09 04:53:10 -04:00
9d4f203ead [ADD] interface: single sources for settings, shortcuts and CSV columns
The generated documentation must list exactly what the screen shows. The
generation settings, the keyboard shortcuts and the CSV columns each live in
one table that both the interface and the documentation read; the target
field of the proposals section reads its entry too. A guard reports any key
named in the interface without its shortcut entry. The LISTE_SUR_VOISINE
warning now shows its remedy, moving the covered neighbour.
Checked: 3116 node and 643 browser tests green from the index alone.

--- FR ---

[ADD] interface : sources uniques des réglages, raccourcis, colonnes CSV

La documentation engendrée doit lister exactement ce que l'écran montre.
Les réglages de la génération, les raccourcis clavier et les colonnes du
CSV vivent chacun dans une table que lisent l'interface et la
documentation ; le champ de la cible des propositions lit aussi la sienne.
Une garde relève toute touche nommée dans l'interface sans son entrée de
raccourci. L'avertissement LISTE_SUR_VOISINE montre désormais son remède,
le déplacement de la voisine couverte.
Vérifié : 3116 node et 643 navigateur verts depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-09 04:51:45 -04:00
0e9ff8c708 [ADD] outputs: dated placement, draft rule, page footer, machine paper
A badge or a printed page must say which placement it shows and whether it
is a draft. The retained plan and each proposal carry an optional
timestamp, set when their placement changes and kept when a command rebuilds
it unchanged, with or without an instant; format 1 is unchanged and the
shipped demonstrations stay byte-identical. Anything but the retained plan
under a retained or locked state prints as a draft, proposals included. The
footer names event, date, round, timestamp and visible version.
Checked: red first; 3085 node and 639 browser tests green from the index.

--- FR ---

[ADD] sorties : placement daté, règle du brouillon, pied, papier

Un badge ou une page imprimée doit dire quel placement il montre et s'il
est un brouillon. Le retenu et chaque proposition portent un horodatage
facultatif, posé quand leur placement change et gardé quand une commande le
reconstruit à l'identique, avec ou sans instant ; le format 1 ne change pas
et les démonstrations livrées restent identiques à l'octet. Tout ce qui
n'est pas le retenu sous l'état retenu ou bloqué s'imprime en brouillon,
propositions comprises. Le pied nomme événement, date, tour, horodatage et
version visible.
Vérifié : rouge d'abord ; 3085 node et 639 navigateur verts depuis l'index.

Assisted-by: Claude Opus 5.5
2026-10-09 04:50:31 -04:00
e1245dcc08 [ADD] outputs: pdf-lib, Noto Sans, paper sizes, badge imposition
Badges and printed views need a PDF writer, an embedded font whose metrics
the tests can measure, and the paper the machine prints on. pdf-lib with
fontkit writes the sheet; Noto Sans (OFL) ships with its provenance and
SHA-256, and travels into www/ with every third-party notice that the
minified bundle drops. The paper is kept per machine in reglages_locaux.json.
A4 and Letter derive the A6 grid from their dimensions; the PDF libraries
load in two deferred chunks, each under the 1000 kB threshold.
Checked: 3048 node, 639 browser and 67 long tests green from the index.

--- FR ---

[ADD] sorties : pdf-lib, Noto Sans, formats de papier, imposition

Les badges et les vues imprimables exigent un producteur de PDF, une police
embarquée que les épreuves mesurent, et le papier de la machine. pdf-lib et
fontkit écrivent la planche ; Noto Sans (OFL) arrive avec sa provenance et
son SHA-256, et voyage dans www/ avec chaque avis de tiers que le paquet
minifié retire. Le papier se garde par machine dans reglages_locaux.json.
A4 et Lettre dérivent la grille A6 de leurs dimensions ; les bibliothèques
PDF se chargent en deux morceaux différés, chacun sous le seuil de 1000 ko.
Vérifié : 3048 node, 639 navigateur et 67 longues vertes depuis l'index.

Assisted-by: Claude Opus 5.5
2026-10-09 04:49:18 -04:00
3028fca2ed [FIX] interface: ghost labels, keyboard, valid HTML, closed data-* list
The drag ghost names what releasing at the point changes, floor included.
Escape on a seat returns to its table, a refused Tab stays put, the legend
toggle exposes aria-expanded, and the header markup is valid HTML. Every
data-* attribute the interface sets belongs to one closed list that a guard
reads. The tree guards follow helpers a test imports, and the reporter says
the whole series stays watched under coverage on a small machine.
Checked: every new test red first; 3001 node, 635 browser and 63 long tests
green from the index alone.

--- FR ---

[FIX] interface : fantôme nommé, clavier, HTML valide, data-* fermés

Le fantôme du glisser nomme ce que relâcher au point modifie, sol compris.
Échap sur un siège remonte à sa table, un Tab refusé reste en place, la
bascule de la légende expose aria-expanded, et la tête est du HTML valide.
Chaque attribut data-* que l'interface pose appartient à une liste fermée
qu'une garde lit. Les gardes de l'arbre suivent les aides qu'une épreuve
importe, et le rapporteur dit la série entière surveillée sous couverture.
Vérifié : chaque épreuve rouge d'abord ; 3001 node, 635 navigateur et 63
longues vertes depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-09 04:02:03 -04:00
d5a1560915 [FIX] core: bounded geometry, dated lock, empty seat, neighbour lists
Non-finite scale ratios, view translations and handle counts now raise
instead of returning 0, NaN or looping forever. The lock carries the
instant from the single clock, a lock taken back in this session's name is
its own, and quitting releases held locks. An empty chair is null only, at
its exact path. A table grown over a neighbour warns LISTE_SUR_VOISINE once
per pair; successive remedies never aim at the same free cell.
Checked: every new test red first; 2983 node and 617 browser tests green
from the index alone.

--- FR ---

[FIX] cœur : géométrie bornée, verrou daté, chaise vide, listes voisines

Un rapport d'échelle, une translation de vue ou un compte de poignée non
finis lèvent au lieu de rendre 0, NaN ou de boucler sans fin. Le verrou
porte l'instant de l'horloge unique, un verrou repris au nom de la séance
est le sien, et quitter rend les verrous tenus. Une chaise vide est null
seulement, à son chemin exact. Une table agrandie sur sa voisine avertit
LISTE_SUR_VOISINE une fois par paire ; les remèdes successifs ne visent
jamais la même case libre.
Vérifié : chaque épreuve rouge d'abord ; 2983 node et 617 navigateur verts
depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-09 04:00:22 -04:00
94ea937ae4 [IMP] home: list shown at once, computed columns loaded per event
The event list waited until every event's ranking was evaluated, about
10 ms per event with propositions, before showing anything. It now shows
as soon as the folder is read; each line's retained-plan columns and best
proposition load one event at a time, yielding to the browser between
events, behind a rotating SVG spinner, and show as each result arrives.
Work for a list no longer shown is dropped. The spinner is the one named
exception to the no-animation rule: still under reduced motion, cancelled
for captures, announced once. Checked: 2935 node, 616 browser, 62 long.

--- FR ---

[IMP] accueil : liste aussitôt montrée, colonnes calculées par événement

La liste des événements attendait l'évaluation du classement de chaque
événement, environ 10 ms par événement qui a des propositions, avant de
rien montrer. Elle paraît dès la lecture du dossier ; les colonnes du
retenu et la meilleure proposition de chaque ligne se chargent un
événement à la fois, le navigateur reprenant la main entre deux, derrière
une icône SVG qui tourne. Le travail d'une liste qui n'est plus montrée
est abandonné. L'icône est la seule exception nommée à l'interdit
d'animation. Vérifié : 2935 node, 616 navigateur, 62 longues.

Assisted-by: Claude Opus 5.5
2026-10-08 17:07:31 -04:00
9eb1275f53 [ADD] home: best ranked proposition on every event line
Each event line of the home lists now names its rank-1 proposition and
its cumulated collisions, whether or not a plan is retained, with the
same label and tooltip as the generation block. One application function
picks the rank-1 proposition for both places, so the list, the generation
block and the propositions table show the same proposition and number.
The list reads the examined charge, as opening the event does, so a file
with a repeated proposition identifier no longer hides the whole folder.
Checked: 2923 node, 609 browser, 62 long tests, from the index alone.

--- FR ---

[ADD] accueil : meilleure proposition classée sur chaque événement

Chaque ligne des listes de l'accueil nomme sa proposition de rang 1 et ses
collisions cumulées, retenu ou non, avec le même libellé et la même
infobulle que le bloc de la génération. Une seule fonction d'application
désigne le rang 1 aux deux endroits : la liste, le bloc et le tableau des
propositions montrent la même proposition et le même nombre. La liste lit
la charge examinée, comme l'ouverture : un fichier dont une proposition
répète un identifiant ne fait plus disparaître tout le dossier.
Vérifié : 2923 node, 609 navigateur, 62 longues, depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-08 06:06:21 -04:00
5fc5ac9205 [ADD] home: retained plan's collisions and redundancy gap per event
The event list showed no outcome, so comparing events meant opening each.
Each line now shows, for the retained plan only, the cumulated collisions
(pair and tour) and the redundancy gap |target - sum of r(p)|, with an
explanation tooltip; an event without a measurable retained plan shows a
dash. The target is set per event in Propositions, 1000 by default: an
optional settings field, absent in every existing file and read as 1000,
written through one undoable command refused in reading mode. Listing
stays read-only. Checked: 2909 node, 604 browser, 62 long tests.

--- FR ---

[ADD] accueil : collisions et Diff de redondance du retenu par événement

La liste des événements ne montrait aucun résultat : comparer obligeait à
ouvrir chacun. Chaque ligne montre, pour le retenu seul, les collisions
cumulées (paire et tour) et la Diff somme d'appartenance, |cible - somme
de r(p)|, avec une infobulle ; sans retenu mesurable, un tiret. La cible
se règle par événement dans Propositions, 1000 par défaut : champ
facultatif des réglages, absent de tout fichier existant et lu 1000, écrit
par une commande qui se défait et se refuse en lecture. La liste reste en
lecture seule. Vérifié : 2909 node, 604 navigateur, 62 longues.

Assisted-by: Claude Opus 5.5
2026-10-08 05:35:48 -04:00
654cde4f10 [ADD] generation: best proposition block with its cumulated collisions
The generation screen gave no sign of where the ranking stood, so the
operator had to switch to the propositions to see whether another run was
worth it. A block at the top now names the rank-1 proposition and its
cumulated collisions (pair and tour), read from the same evaluation table
as the propositions, with the same explanation tooltip. It says so in
words when no proposition is ranked, and stays visible in reading mode,
on a blocked plan and during a generation.
Checked: 2886 node, 599 browser tests, from the index alone.

--- FR ---

[ADD] génération : bloc de la meilleure proposition, collisions cumulées

L'écran de génération ne disait rien du classement : l'opérateur devait
passer aux propositions pour juger si une autre génération valait la
peine. Un bloc en tête nomme la proposition de rang 1 et ses collisions
cumulées (paire et tour), lues dans la même table d'évaluation que les
propositions, avec la même infobulle d'explication. Il le dit en mots
quand aucune proposition n'est classée, et reste visible en lecture, sur
un plan bloqué et pendant une génération.
Vérifié : 2886 node, 599 navigateur, depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-08 05:27:32 -04:00
afdad31ef3 [ADD] propositions: explanation tooltips on criteria and column headers
The propositions table names its measures with the glossary's terms, which
an organiser cannot be expected to know. Each ranking criterion of the
order sentence and each column header now shows a short explanation on
hover or keyboard focus: what the number counts and whether lower or
higher is better, written from the spec and the engine. The tooltip is a
reusable primitive, read through aria-describedby, kept in the window,
never over its word, closed by Escape; the rendering guards measure it.
Checked: 2882 node, 592 browser tests, from the index alone.

--- FR ---

[ADD] propositions : infobulles d'explication des critères et colonnes

Le tableau des propositions nomme ses mesures par les termes du glossaire,
qu'un organisateur n'a pas à connaître. Chaque critère de la phrase de
l'ordre et chaque en-tête de colonne montre une courte explication au
survol ou au focus : ce que compte le nombre, et s'il vaut mieux bas ou
haut, écrite d'après le spec et le moteur. L'infobulle est une primitive
réutilisable, lue par aria-describedby, gardée dans la fenêtre, jamais sur
son mot, fermée par Échap ; les gardes du rendu la mesurent.
Vérifié : 2882 node, 592 navigateur, depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-08 04:56:52 -04:00
b969304c2a [ADD] generation: a pool of workers over the CPUs, cores setting
Generation ran in a single worker, one proposition after another, using
one core. A pool of workers now takes propositions by rank, as many as
the cores set: automatic by default (every logical CPU), or a count from
1 to that number. Each proposition is still computed from its own derived
seed, so the result is byte-identical whatever the core count, ordered by
identifier. One progress bar sums the workers; Cancel stops them all; the
duration estimate counts the cores. The setting is per session and never
written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron.

--- FR ---

[ADD] génération : réserve de travailleurs sur les processeurs, cœurs

La génération tournait dans un seul travailleur, une proposition après
l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les
propositions par rang, autant que de cœurs réglés : automatique par défaut
(tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque
proposition se calcule toujours depuis sa graine dérivée : le résultat est
identique à l'octet quel que soit le nombre de cœurs, rangé par
identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte
les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62.

Assisted-by: Claude Opus 5.5
2026-10-08 04:35:21 -04:00
8afa53ebba [ADD] plan: one hue and pattern per conflict rule, legend, appartenance
The plan drew every conflict in one hue, so a table that seats colleagues
together looked like one where people meet again. Each active rule now has
its own reserved hue and pattern: same appartenance hatched one way, met
again hatched the other, back at a table dotted; rules on one table
overlap, the badge keeps the total. A legend from the view bar shows each
active rule's sample. A table's tooltip names the appartenance that brings
a pair together. The hues are validated by computation in both themes and
the spec (7.5, 12.7) follows. Checked: 2848 node, 580 browser tests.

--- FR ---

[ADD] plan : une teinte et une trame par règle, légende, appartenance

Le plan dessinait tout conflit d'une seule teinte : une table qui réunit
des collègues ressemblait à une table où des gens se revoient. Chaque
règle active a sa teinte réservée et sa trame : même appartenance hachurée
dans un sens, voisins revus dans l'autre, table revue en pointillé ; les
règles d'une table se superposent, la pastille garde le total. Une légende
dans la barre de vue montre l'échantillon de chaque règle active.
L'infobulle nomme l'appartenance qui réunit une paire. Teintes validées
par calcul dans les deux thèmes ; spec § 7.5, § 12.7. Vérifié : 2848, 580.

Assisted-by: Claude Opus 5.5
2026-10-08 04:33:43 -04:00
5f62698c82 [ADD] participants: conflicts of the shown plan inside the list groups
When the list is grouped and a proposition is shown, or a plan retained,
each group whose people are in a conflict carries a mark and a count, and
lists every conflict: the tour, the table number, the people, and the
rule broken (same appartenance, met again, back at a table). The
conflicts are read from the engine's per-table conflicts, as the plan
reads them, from the same placement and the same earlier tours, so both
screens give the same numbers. Nothing is written to the event.
Checked: 2831 node, 571 browser tests, from the index alone.

--- FR ---

[ADD] participants : conflits du plan montré dans les groupes

Quand la liste est groupée et qu'une proposition est montrée, ou un plan
retenu, chaque groupe dont des personnes sont en conflit porte une marque
et un compte, et liste chaque conflit : le tour, le numéro de table, les
personnes et la règle enfreinte (même appartenance, se revoient, revient à
une table). Les conflits se lisent dans ceux du moteur par table, comme le
plan, sur le même placement et les mêmes tours antérieurs : les deux
écrans donnent les mêmes chiffres. Rien ne s'écrit dans l'événement.
Vérifié : 2831 node, 571 navigateur, depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-08 04:32:30 -04:00
fbff3a6c5f [ADD] participants: group the list by columns, with counts and collapse
The participants list can now be grouped by one or more columns, nested
level by level: appartenance (by its normalised key, labelled with its
first spelling), status, exclusion, or any text column. Each group header
shows its value, its count and a keyboard-operable collapse button, with
Collapse all and Expand all. The filter applies first, groups follow the
current sort, arrow keys skip headers and collapsed rows, and an edit
moves its row to its new group. Grouping is session state only and never
writes the event. Checked: 2811 node, 565 browser tests, index alone.

--- FR ---

[ADD] participants : grouper la liste par colonnes, compte et repli

La liste des participants se groupe par une ou plusieurs colonnes,
imbriquées niveau par niveau : appartenance (par sa clé normalisée, sous sa
première orthographe), statut, exclusion, ou toute colonne de texte.
Chaque en-tête de groupe montre sa valeur, son compte et un bouton de
repli au clavier, avec Tout replier et Tout déplier. Le filtre s'applique
d'abord, les groupes suivent le tri, les flèches sautent les en-têtes et
les lignes repliées, et une saisie déplace sa ligne dans son nouveau
groupe. État de séance seul, aucune écriture. Vérifié : 2811 node, 565.

Assisted-by: Claude Opus 5.5
2026-10-08 03:49:36 -04:00
57a2642b99 [ADD] propositions: a ranking criterion highlights its table column
The order sentence names the ranking criteria, but nothing tied a name to
the column holding its value. Each criterion name, and « l'identifiant
croissant », now highlights its column when hovered or focused: the header
and every cell get heavier side borders and the header an underline, so
text contrast is unchanged and the cue is not colour alone. The mapping
from criterion to column lives in the propositions model, and a criterion
without a column fails there. The sentence still reads word for word.
Checked: 2780 node, 554 browser tests, from the index alone.

--- FR ---

[ADD] propositions : un critère du classement surligne sa colonne

La phrase de l'ordre nomme les critères, mais rien ne reliait un nom à la
colonne qui porte sa valeur. Chaque nom de critère, et « l'identifiant
croissant », surligne maintenant sa colonne au survol ou au focus : l'en-
tête et chaque cellule prennent des bords latéraux plus épais et l'en-tête
un soulignement ; le contraste du texte ne change pas, le signe ne tient
pas qu'à la couleur. Le lien critère-colonne vit dans le modèle, et un
critère sans colonne y lève. La phrase se lit mot pour mot comme avant.
Vérifié : 2780 node, 554 navigateur, depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-08 03:39:25 -04:00
fca74b6672 [ADD] tests: spec coverage guards, delivery checks, spec corrections
New guards close the spec coverage gaps: only the configuration and the
diagnostic read reservations in the engine, no second language in the
sources, the engine and geometry never read the version, a test lives
beside its module, fixtures never copy a shipped file, and the property
library stays in a closed list. The delivery test pins the www output and
the French language passed by the entry point. The spec names three test
projects and the three shell files. Checked: 2778 node, 550 browser and
62 long tests from the index alone; the version check passes.

--- FR ---

[ADD] épreuves : gardes de couverture du spec, livrable, spec corrigé

De nouvelles gardes ferment les manques de couverture : seules la
configuration et le diagnostic lisent les réservations dans le moteur,
aucun second langage dans les sources, le moteur et la géométrie ne lisent
pas la version, une épreuve vit près de son module, aucune donnée d'épreuve
ne copie un fichier livré, la bibliothèque de propriétés reste en liste
fermée. Le livrable fige la sortie www et la langue française du point
d'entrée. Le spec nomme trois projets et trois fichiers de coquille.
Vérifié : 2778 node, 550 navigateur, 62 longues ; version conforme.

Assisted-by: Claude Opus 5.5
2026-10-07 17:51:49 -04:00
ddd587da87 [FIX] iteration 3 review: seat targets, gestures, warnings, settings
The wheel no longer zooms during a gesture, so a drop lands under the
ghost. A seat is a target the size of its pitch. A floor drop refuses to
remove an every-tour reservation. A seat reservation the retained plan
does not hold is flagged at the seat, with its swap as remedy. DERIVE names
the person; capacities have an upper bound; Generate waits for a pending
setting; a worker that fails to load shows a refusal; § 5.3 constraints
get their switches. Commands are not re-entrant and a double click does not
confirm. Checked: 2755 node, 550 browser tests, from the index alone.

--- FR ---

[FIX] revue de l'itération 3 : cibles, gestes, avertissements, réglages

La molette ne zoome plus pendant un geste : le dépôt tombe sous le fantôme.
Un siège est une cible de la taille de son pas. Un dépôt sur le sol refuse
de retirer une réservation de tous les tours. Une réservation à un siège
que le retenu ne tient pas est relevée au siège, l'échange en remède. La
dérive nomme la personne ; les capacités ont une borne ; Générer attend un
réglage en cours ; un travailleur qui ne se charge pas donne un refus ; le
§ 5.3 a ses bascules. Les commandes ne sont pas ré-entrantes et un double
clic ne confirme pas. Vérifié : 2755 node, 550 navigateur, index seul.

Assisted-by: Claude Opus 5.5
2026-10-07 17:50:35 -04:00
b3d59f2079 [ADD] interface: operator walk, reading order, windows, read-only mode
One walk at 1366 x 700, by gestures only from a fresh folder: create an
event, import the edge-case CSV, sort and filter, tables, default and
tours, the plan at scale, two hosts, a refusal on its place, three
propositions retained, an adjustment, then reading mode where every plan
gesture leaves the state untouched and undo is refused. Non-destructive
gestures open no window; destructive ones name exactly what leaves, and
Cancel writes nothing. In reading mode and on a blocked plan, every gesture
family writes nothing. Checked: 517 browser tests, from the index alone.

--- FR ---

[ADD] interface : parcours, ordre libre, fenêtres, gestes en lecture

Un parcours à 1366 x 700, par gestes depuis un dossier neuf : créer un
événement, importer le CSV des cas limites, trier et filtrer, tables,
défaut et tours, le plan à l'échelle, deux animateurs, un refus sur sa
place, trois propositions dont une retenue, un ajustement, puis la lecture
où chaque geste du plan laisse l'état intact et défaire est refusé. Un geste
non destructeur n'ouvre aucune fenêtre ; un destructeur nomme exactement ce
qui part, et Annuler n'écrit rien. En lecture et sur un plan bloqué, aucune
famille de gestes n'écrit. Vérifié : 517 épreuves navigateur, index seul.

Assisted-by: Claude Opus 5.5
2026-10-07 16:02:33 -04:00
8186b06713 [FIX] event: page never scrolls, broken-support remedies always shown
At 1366 x 700 an open event that shows warnings no longer scrolls the page:
the warnings scroll within their zone and the plan keeps at least 75 % of
its height. A broken support never shrinks, so its three remedies stay in
view, the only way to write the event elsewhere (spec 8.6). Tests now
prove the working-folder path and duplicate nodes are visible, the guard
of « Remplacer » in import, and which header a refused re-alignment shows.
Checked: 2692 node, 499 browser tests, from the index alone.

--- FR ---

[FIX] événement : sans défilement, remèdes du support rompu visibles

À 1366 x 700, un événement ouvert qui montre des avertissements ne fait
plus défiler la page : les avertissements défilent dans leur zone et le
plan garde au moins 75 % de sa hauteur. Un support rompu ne rétrécit
jamais : ses trois remèdes, seul moyen d'écrire l'événement ailleurs
(§ 8.6), restent visibles. Les épreuves prouvent que le chemin et les
doublons du dossier sont visibles, la garde de « Remplacer » à l'import, et
l'en-tête que montre un réalignement refusé. Vérifié : 2692 node, 499.

Assisted-by: Claude Opus 5.5
2026-10-07 15:05:59 -04:00
a2812cddb9 [FIX] plan: named warning, one places state, highlight, table spacing
The unheld-reservation warning names the person and the table number
instead of their identifiers. The places state is computed once per change
and handed to the side panels, not once per panel. A person can be
highlighted from their menu or from the grid, and the view bar names them.
A created table takes a cell a full pitch away from every table, its own
capacity included, so no name list runs over a neighbour's chairs. The
rendering guards fail on an empty walk and also check focus and selection.
Checked: 2692 node, 496 browser, 60 long tests, from the index alone.

--- FR ---

[FIX] plan : avertissement nommé, état des places unique, évidence, pas

L'avertissement de réservation non honorée nomme la personne et le numéro
de la table plutôt que leurs identifiants. L'état des places se calcule une
fois par changement et passe aux panneaux, non une fois par panneau. Une
personne se met en évidence par son menu ou depuis la grille, et la barre
de vue la nomme. Une table créée prend une case à un pas plein de chaque
table, sa capacité comprise : aucune liste ne court sur les chaises
voisines. Les gardes du rendu échouent sur un parcours vide et éprouvent
aussi le focus et la sélection. Vérifié : 2692 node, 496 navigateur, 60.

Assisted-by: Claude Opus 5.5
2026-10-07 15:05:01 -04:00
71b9e75363 [ADD] interface: cross-screen rendering checks, frame marks, badge plate
A screen walker reaches every screen of the iteration by gestures; on each,
in both themes, text holds 4.5:1 and marks 3:1 against what is painted
under them, every text passes through the translation tables, the conflict
hue paints only conflict marks, and no state differs by colour alone. Mode
frames now carry their mark, the count badge sits on a plate over the
conflict hatch, the name list clears the focus square, the participant form
is novalidate. Demonstrations space columns so a name list never runs over
a neighbour's chairs. Checked: 2676 node, 489 browser, 60 long tests.

--- FR ---

[ADD] interface : rendu transversal, marques des cadres, socle, pastille

Un parcours atteint par gestes chaque écran de l'itération ; sur chacun,
dans les deux thèmes, le texte tient 4,5:1 et les marques 3:1 sur ce qui
est peint dessous, tout texte passe par les tables de libellés, la teinte
de conflit ne peint que les marques de conflit, et aucun état ne diffère par
la seule couleur. Les cadres de mode portent leur marque, la pastille pose
sur un socle au-dessus de la trame, la liste des noms s'écarte du focus, le
formulaire est novalidate. Les démonstrations espacent leurs colonnes : une
liste ne court plus sur les chaises voisines. Vérifié : 2676, 489, 60.

Assisted-by: Claude Opus 5.5
2026-10-07 15:06:27 -04:00
819a3853e5 [ADD] application: command registry tested whole, remedy on tour removal
Every command of the registry has an accepted, a refused and, when it
admits one, a no-effect example. In reading mode or on a blocked plan
nothing is written; in writing mode one journal entry precedes the state,
undo restores the charge, a refusal writes nothing and names its remedy
unless it is on the admitted null-remedy list. Removing a reserved person
from a tour now offers « Retirer la réservation ». The invariant checker
runs on each retouch, at opening and after undo, redo and revert.
Checked: 2673 node tests, from the index alone.

--- FR ---

[ADD] application : registre des commandes éprouvé en entier, remède

Chaque commande du registre a un exemple accepté, un refusé et, quand elle
en admet un, un sans effet. En lecture ou sur un plan bloqué rien ne
s'écrit ; en écriture une entrée de journal précède l'état, défaire rend la
charge, un refus n'écrit rien et nomme son remède, hors de la liste des
remèdes nuls admis. Retirer d'un tour une personne réservée propose
désormais « Retirer la réservation ». Le vérificateur d'invariants s'appelle
à chaque retouche, à l'ouverture, après défaire, refaire et revenir.
Vérifié : 2673 épreuves node, depuis l'index seul.

Assisted-by: Claude Opus 5.5
2026-10-07 13:21:37 -04:00
4b442ded14 [ADD] tests: guards for layers, clock, sources, colours, watch patterns
Guards scan the tree file by file and line by line, fail on an empty scan,
and are each shown red on a temporary tree. They cover the interface import
graph, the Electron bridge, one clock, refused dependencies, how tests are
written, hard-coded strings, translation keys, forbidden words, colours and
the conflict hue, markup, pruned selectors and watch patterns. Coverage
keeps the engine integration test on a small machine. Fixes: delays in
tests, the conflict hatch class; « la rend évitable » is a named exception
(§ 5.6). Checked: 2587 node, 465 browser tests, from the index alone.

--- FR ---

[ADD] épreuves : gardes des couches, horloge, sources, couleurs, motifs

Les gardes relèvent par fichier et par ligne, échouent sur un balayage vide
et sont chacune montrées rouges sur un arbre temporaire. Elles couvrent le
graphe d'imports de l'interface, le pont d'Electron, l'horloge unique, les
dépendances refusées, l'écriture des épreuves, les chaînes en dur, les clés
de traduction, les mots interdits, les couleurs et la teinte de conflit, le
balisage, les sélecteurs élagués et les motifs de surveillance. Corrigés :
délais d'épreuves, classe de la trame de conflit ; « la rend évitable » est
une exception nommée (§ 5.6). Vérifié : 2587 node, 465 navigateur.

Assisted-by: Claude Opus 5.5
2026-10-07 13:21:21 -04:00
811cd16b76 [ADD] interface: plan keyboard, tooltip, side panels, person menu, lists
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
2026-10-07 11:08:59 -04:00
7f3dad24af [ADD] interface: plan gestures — drag a person, a table, a handle
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
2026-10-07 10:01:21 -04:00
626159db5f [ADD] interface: diagnostic — what a configuration makes unavoidable
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
2026-10-07 09:41:51 -04:00
ad19131954 [ADD] interface: propositions — ranked table, retain, clear
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
2026-10-07 09:10:39 -04:00
d19394957f [ADD] interface: generation screen — settings, progress, worker, cancel
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
2026-10-07 09:10:12 -04:00
682e69876b [ADD] interface: plan view — zoom, framing, fit, scale, side panels
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
2026-10-07 09:09:45 -04:00
134e7850b7 [ADD] interface: event list, open event, participants, import, plan
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
2026-10-07 08:12:27 -04:00
5fbbab6477 [ADD] interface: application shell — banner, sections, theme, about
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
2026-10-07 07:22:05 -04:00
876ea0f2ce [ADD] interface: primitives — field, refusal, confirmation, command
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
2026-10-07 07:21:20 -04:00
cc6b9fe996 [ADD] application: generation controller, worker, evaluation table
Generating must never block the screen or record a plan that breaks a
rule. The controller refuses before launching, in a fixed order: an
out-of-range setting named by the engine's own check, the session's
refusals, then what makes the run useless. It runs the search in a worker
or in the thread, records only propositions whose invariants hold, skips
plans already present, and keeps the last duration for the session only.
The evaluation table ranks propositions on the minimum of encounters and
names the reservations a proposition does not honour.
Checked: 2112 node and 60 node-long tests; coverage floors kept.

--- FR ---

[ADD] application : génération, travailleur, table d'évaluation

Générer ne doit jamais bloquer l'écran ni enregistrer un plan qui enfreint
une règle. Le contrôleur refuse avant tout lancement, dans un ordre fixe :
un réglage hors de son domaine, nommé par la règle même du moteur, les
refus de la séance, puis ce qui rend le calcul vain. Il lance la recherche
dans un travailleur ou dans le fil, n'enregistre que les propositions dont
les invariants tiennent, écarte les plans déjà présents, et garde la
dernière durée pour la seule séance. La table d'évaluation classe les
propositions sur le minimum de rencontres et nomme les réservations
qu'une proposition ne tient pas.
Vérifié : 2112 node et 60 node-long ; seuils de couverture tenus.

Assisted-by: Claude Opus 5.5
2026-10-07 06:09:45 -04:00
964532fa19 [ADD] application: furniture — tables, default, tours, capacity checks
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
2026-10-07 05:12:43 -04:00
abae4fa9b8 [ADD] application: observable session, events facade, places and seats
The screens of iteration 3 need state they can subscribe to and commands
that keep the plan sound. The session follows the Svelte store contract,
unblocks a plan, cancels a gesture, keeps the framing, and orders the
warnings of a gesture. The facade lists events, settles the working folder
and runs copy, rename, import and delete. Places cover reservations, titles,
designation and the retained plan: each gesture reads seats as the display
shows them, reserved people keep their table, and a person removed frees
her chair while every other seat stays.
Checked: 1973 node, 127 browser, 60 node-long tests; coverage floors kept.

--- FR ---

[ADD] application : séance observable, façade des événements, places

Les écrans de l'itération 3 exigent un état auquel s'abonner et des
commandes qui gardent le plan sain. La séance suit le contrat des magasins
de Svelte, débloque un plan, annule un geste, garde le cadrage et ordonne
les avertissements d'un geste. La façade liste les événements, règle le
dossier de travail et mène copie, renommage, import et suppression. Les
places couvrent réservations, titres, désignation et plan retenu : chaque
geste lit les sièges comme l'écran les montre, une personne réservée garde
sa table, et une personne retirée libère sa chaise sans déplacer les autres.
Vérifié : 1973 node, 127 navigateur, 60 node-long ; seuils de couverture.

Assisted-by: Claude Opus 5.5
2026-10-07 04:14:24 -04:00
f76c5dede5 [ADD] tests: browser tooling — reachable entries, real colours, contrast
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
2026-10-07 04:13:34 -04:00
82e57f47df [FIX] web storage: refuse a name Chromium did not convert, UTF-8 launch
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
2026-10-07 02:35:12 -04:00
71076afe4d [ADD] application: clock, translation, formatting, displayed name
The screens need one clock, one translation mechanism and one way to
format and name, or each component grows its own. horloge.js is the only
code that reads time and arms timers, injected so tests drive it.
traduction.js keys texts by domain, in two families of tables, raises on a
missing key and never shows a raw key; libelles/ splits the label table by
domain. format.js formats numbers and dates in French, and personnes.js
composes the displayed name the frozen labels use. Nothing persists
between sessions.
Checked: 1773 node and 43 browser tests.

--- FR ---

[ADD] application : horloge, traduction, mise en forme, nom affiché

Les écrans exigent une horloge, un mécanisme de traduction et une façon de
mettre en forme et de nommer, sans quoi chaque composant ferait les siens.
horloge.js est le seul code qui lit l'heure et arme des minuteries, injecté
pour que les épreuves le pilotent. traduction.js range les textes par
domaine, en deux familles de tables, lève sur une clé absente et ne montre
jamais une clé brute ; libelles/ découpe la table des libellés par domaine.
format.js met en forme nombres et dates en français, et personnes.js
compose le nom affiché qu'emploient les libellés figés. Rien ne persiste
d'une séance à l'autre.
Vérifié : 1773 node et 43 navigateur.

Assisted-by: Claude Opus 5.5
2026-10-07 02:33:39 -04:00
63b997faa9 [ADD] interface: colour tokens, two themes, checked palette, marks
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
2026-10-07 02:33:30 -04:00
eec14bdcb0 [ADD] geometry: tables, their chairs, designating a seat
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
2026-10-07 02:32:47 -04:00
1ea572468d [ADD] geometry: plan view, truncation, scale bar, measured constants
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
2026-10-07 02:32:35 -04:00
7667134bd7 [ADD] engine: conflicts per table, aggregated diversity, diagnosis extras
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
2026-10-07 02:32:12 -04:00
03c04bdf16 [ADD] storage: empty chair in a table list when seats are assigned
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
2026-10-07 02:31:26 -04:00
63efdb21a1 [FIX] matrix: UTF-8 locale for Chromium, skip ps reading when absent
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
2026-10-07 02:14:19 -04:00
8d03d5ba41 [FIX] electron: lock liveness only when certain, retries on every write
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
2026-10-07 02:00:36 -04:00
c72215a2da [FIX] csv: update matching, stray quotes, preview by import mode
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
2026-10-07 01:20:50 -04:00
0bc48fa1ae [FIX] storage, session: strict UTF-8, lost journal, lock, exclusions
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
2026-10-07 01:20:42 -04:00
67fd0bc9ff [ADD] application: end-to-end test of the operator's path
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
2026-10-06 23:40:46 -04:00
a1cac443bb [FIX] session: undo never moves id counters back
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
2026-10-06 23:40:40 -04:00
9530eca507 [ADD] application: session, named commands, French label table
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
2026-10-06 23:17:36 -04:00
a3d7badf6d [ADD] storage: copy, rename, import, delete events; local settings
§ 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
2026-10-06 23:17:05 -04:00
220814a673 [ADD] storage: measured cost of a complete save on the big demo
§ 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
2026-10-06 23:05:57 -04:00
fa32ad9fae [ADD] storage: event store — list, create, open, save, recover
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
2026-10-06 20:39:49 -04:00
15148e3a26 [FIX] storage: compact seat patches, checked poses, 32-bit identifiers
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
2026-10-06 19:22:02 -04:00
f2b66f2f92 [ADD] electron: confined file system, atomic writes, lock, bridge
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
2026-10-06 17:34:31 -04:00
99524aa9bf [ADD] storage: web file system over the origin private file system
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
2026-10-06 17:03:45 -04:00
2bca543e7e [ADD] demo: delivered event files, example CSVs, payload fingerprint
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
2026-10-06 17:03:15 -04:00
201259331d [ADD] csv: apply an import three ways, re-export refusals, export list
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
2026-10-06 14:47:25 -04:00
3b00566560 [ADD] storage: working-folder rule, portable data/ or Documents
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
2026-10-06 14:47:22 -04:00
4003b1f833 [ADD] storage: append-only journal, snapshots every fifty, undo threads
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
2026-10-06 14:45:56 -04:00
35cc5f5f75 [ADD] csv: columns by header, closed exclu values, mandatory preview
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
2026-10-06 13:12:28 -04:00
fdaa79ed32 [ADD] storage: file-system interface, failing test double, contract
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
2026-10-06 13:12:25 -04:00
f24896c4a1 [ADD] storage: patches between two payloads, keyed by record id
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
2026-10-06 13:12:23 -04:00
d0f4081961 [ADD] storage: positional placements, faulty versus stale propositions
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
2026-10-06 13:12:20 -04:00
e1ea16d244 [ADD] storage: event file names that Windows accepts, bounded paths
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
2026-10-06 13:11:37 -04:00
1d15ebaf68 [ADD] storage: event document, canonical form, consistency check
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
2026-10-06 13:11:34 -04:00
dd088f2dd9 [ADD] csv: decode in four steps, choose the separator, cut records
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
2026-10-06 07:05:21 -04:00
1910e207cb [FIX] tests: four-core budget, quoted values, key guard, switch floor
The relaunch budget of § 14.14 was out of reach on two cores whatever the
tests did; the spec now names its reference machine, four cores, and the
watched series drops a 200 000-move search the long series already runs.
The itinerary guard quotes a string value as the indexed-plan guard does,
through one shared helper. The key-order guard no longer mistakes the
JSDoc type {Object[]} for a computed access, and the property grid counts
the proposals that switch to the constraint order, under a floor.

Checked: 456 node tests in 1.8 s; each new test failed first; cutting the
descent to one move drops the switch count from 86 to 30, under its floor.

--- FR ---

[FIX] épreuves : budget sur quatre cœurs, citation, clés, bascule

Le budget de relance du § 14.14 était hors d'atteinte sur deux cœurs,
quoi que fassent les épreuves ; le spec nomme désormais sa machine de
référence, quatre cœurs, et la série surveillée quitte une recherche de
200 000 mouvements que la série longue joue déjà. La garde d'itinéraire
cite une chaîne comme la garde du plan indexé, par un seul assistant. La
garde de l'ordre des clés ne prend plus le type JSDoc {Object[]} pour un
accès calculé, et la grille compte, sous un plancher, les propositions
qui basculent dans l'ordre des contraintes.

Vérifié : 456 épreuves node en 1,8 s ; chaque épreuve nouvelle a échoué
d'abord ; une descente coupée au premier mouvement fait tomber les
bascules de 86 à 30, sous leur plancher.

Assisted-by: Claude Opus 5.5
2026-10-06 04:26:08 -04:00
4795114093 [ADD] tests: budget reporter, one import parser, key-order guard
The time budget of § 14.14 had no enforcement: a reporter now prints the
total and the ten slowest tests, and fails a run whose node project
exceeds 30 s or node-long 60 s. Two guards parsed imports with two
patterns, one blind past an apostrophe in a comment; both now use one
parser anchored on « from ». The determinism guard refuses key-order
walks, and one test binds the application name across its three
declarations. The end-to-end generations drop to 100 000 moves.

Checked: each ceiling, the apostrophe case and a key walk are shown
failing before the guard that catches them.

--- FR ---

[ADD] épreuves : rapporteur de budget, imports, ordre des clés

Le budget de temps du § 14.14 n'avait aucune garde : un rapporteur
imprime désormais la durée totale et les dix épreuves les plus lentes,
et fait échouer une exécution dont le projet node dépasse 30 s ou
node-long 60 s. Deux gardes lisaient les imports par deux motifs, l'un
aveugle après une apostrophe en commentaire ; les deux passent par un
seul analyseur ancré sur « from ». La garde de déterminisme refuse les
parcours de clés, et une épreuve lie le nom de l'application à ses
trois déclarations. Les générations de bout en bout passent à 100 000.

Vérifié : chaque plafond, le cas de l'apostrophe et un parcours de clés
sont montrés en échec avant la garde qui les attrape.

Assisted-by: Claude Opus 5.5
2026-10-06 04:23:13 -04:00
6c67cba949 [IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.

Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.

--- FR ---

[IMP] moteur : propriétaires uniques, régénération, grille de propriétés

La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.

Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.

Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
c7cd5f9142 [ADD] engine: end-to-end runs on the demonstrations, measured thresholds
The whole chain — search, both verifiers, measure, ceilings, ranking —
runs end to end on the demonstrations. At 500 000 moves the large one
reaches its proven floor: largest gap 1, no collision, no repeat. Its
quality thresholds were set after measurement, with the measurement in
the comment, never guessed.

Checked: small at 8 for all and certified; conflict variant spreads its 4
collisions over 4 pairs; large at gap 1 with 99 imposed returns; the
ranking holds when its order differs from id order.

--- FR ---

[ADD] moteur : la chaîne de bout en bout, seuils posés après mesure

Toute la chaîne — recherche, les deux vérificateurs, mesure, plafonds,
classement — tourne de bout en bout sur les démonstrations. À 500 000
mouvements, la grande atteint son plancher prouvé : écart maximal 1,
aucune collision, aucune répétition. Ses seuils de qualité sont posés
après mesure, la mesure en commentaire, jamais de tête.

Vérifié : petite à 8 pour tous et certifiée ; variante en conflit à 4
collisions sur 4 paires ; grande à l'écart 1 avec 99 retours imposés ; le
classement tient quand son ordre diffère de celui des identifiants.

Assisted-by: Claude Opus 5.5
2026-10-05 22:52:30 -04:00
f8b3e8b0a9 [ADD] engine: lack, its three figures, dominance and the ranking
Raw meeting counts stop comparing proposals once a table is incomplete;
the lack, realised ceiling minus encounters, compares them. The module
gives the three figures of § 12.10.4, the sorted lack profile, rank
counts and profile dominance between two proposals, and the minimum
certificate read against the a priori ceiling. The ranking orders by gap,
then collision excess, cumulative collisions, repeats and redundancy.

Checked: the operator's three plans rank by excess 0, 2, 3, which either
count alone would invert; dominance and switch rank are pinned by hand.

--- FR ---

[ADD] moteur : manque, ses trois chiffres, dominance et classement

Les nombres bruts de rencontres cessent de comparer deux propositions dès
qu'une table est incomplète ; le manque, plafond réalisé moins
rencontres, les compare. Le module rend les trois chiffres du
§ 12.10.4, le profil trié du manque, le décompte des rangs et la
dominance de profil entre deux propositions, et le certificat de minimum
lu contre le plafond a priori. Le classement ordonne par écart, puis
excédent de collisions, collisions cumulées, répétitions et redondance.

Vérifié : les trois plans de l'opérateur se classent par excédent 0, 2,
3, ce que chaque compte seul inverserait ; dominance et rang de bascule
épinglés à la main.

Assisted-by: Claude Opus 5.5
2026-10-05 22:52:29 -04:00
f5d1bb04bd [ADD] engine: diagnosis of what a configuration makes unavoidable
Before any search, the diagnosis states what no plan can avoid: missing
seats, the a priori ceiling, per-group collision floors in cumulative
occurrences, distinct pairs and excess, imposed returns, anchoring per
table, and the floor of the itinerary gap where the room is tight. A
floor it cannot prove is null, never zero, so the operator is never sent
to rerun towards a value the configuration forbids.

Checked: the large demonstration gives a floor of 1 with at least 24
mobiles; collision floors equal exact minima found by enumeration, the
§ 5.6 example of 8 collisions on 2 pairs included.

--- FR ---

[ADD] moteur : diagnostic de ce qu'une configuration rend inévitable

Avant toute recherche, le diagnostic énonce ce qu'aucun plan n'évite :
places manquantes, plafond a priori, planchers de collisions par groupe
en occurrences cumulées, paires distinctes et excédent, retours imposés,
ancrage par table, et le plancher de l'écart d'itinéraire là où la salle
est tendue. Un plancher qu'il ne sait pas prouver vaut null, jamais
zéro : l'opérateur n'est jamais envoyé relancer vers une valeur que la
configuration interdit.

Vérifié : la grande démonstration donne un plancher de 1 pour 24 mobiles
au moins ; les planchers de collisions égalent les minimums exacts
trouvés par énumération, l'exemple du § 5.6 compris.

Assisted-by: Claude Opus 5.5
2026-10-05 22:52:29 -04:00
74c21ee031 [ADD] search: seeded late acceptance over a lexicographic score
A proposition is the best plan a late-acceptance descent finds from its
derived seed. It stops on a count of moves, never on a duration, so one
seed gives one plan on any machine. The score is a six-integer tuple
compared lexicographically: largest gap to the a priori ceiling, sum of
squared gaps, collision excess, cumulative collisions, repeats with chosen
returns, redundancy. An incremental state scores a swap in O(capacity);
the full recomputation, from the measure, checks it.

Checked: the small demonstration reaches 8 met for all twelve with no
special case; incremental and full scores agree up to 10 000 moves.

--- FR ---

[ADD] recherche : acceptation tardive ensemencée, score lexicographique

Une proposition est le meilleur plan que trouve une descente par
acceptation tardive depuis sa graine dérivée. Elle s'arrête sur un compte
de mouvements, jamais sur une durée : une graine donne un plan sur toute
machine. Le score est un n-uplet de six entiers comparé dans l'ordre
lexicographique : plus grand écart au plafond a priori, somme des carrés
des écarts, excédent de collisions, collisions cumulées, répétitions et
retours choisis, redondance. Un état incrémental évalue un échange en
O(capacité) ; le recalcul complet, tiré de la mesure, le vérifie.

Vérifié : la petite démonstration atteint 8 rencontres pour les douze sans
cas particulier ; scores incrémental et complet s'accordent jusqu'à
10 000 mouvements.

Assisted-by: Claude Opus 5.5
2026-10-05 22:52:29 -04:00
a2a3a7eca8 [ADD] demo: four seeded configurations, forged names, witness round
The demonstrations are built from a seed in a fixed draw order. The large
one seats 260 at 29 tables of 8 and 4 of 7 with one facilitator each, its
variant at 33 tables of 8; the small one seats 12 at four tables of 3 in
groups 4/4/4, its conflict variant 5/4/3. Group sizes follow the weighted
law, a seed with no witness round is refused, and forged names appear
nowhere else in the repository.

Checked: the large configuration is tight at 260 seats; each of the four
refusals raises its named error; a wrong table split fails 12 tests.

--- FR ---

[ADD] demo : quatre configurations ensemencées, noms forgés, tour témoin

Les démonstrations se construisent depuis une graine, dans un ordre de
tirages fixé. La grande assoit 260 personnes à 29 tables de 8 et 4 de 7,
un animateur par table, sa variante à 33 tables de 8 ; la petite assoit
12 personnes à quatre tables de 3 en groupes 4/4/4, sa variante de
conflit 5/4/3. Les tailles de groupe suivent la loi pondérée, une graine
sans tour témoin est refusée, et les noms forgés n'apparaissent nulle
part ailleurs dans le dépôt.

Vérifié : la grande configuration est tendue à 260 sièges ; chacun des
quatre refus lève son erreur nommée ; une mauvaise répartition des tables
fait échouer 12 épreuves.

Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
926a3ff21f [ADD] engine: invariant and indicator verifiers, as application code
Both verifiers ship with the application and run on every generation and
every loaded file: the first judges a plan against the instance, the
second the line N − 1 ≥ a priori ≥ realised ≥ met for each person. Neither
throws on a content defect — each defect is a named violation — and
neither modifies what it receives.

Checked: one mutation per violation code yields that violation and no
other; frozen inputs stay intact; three mutants that wrote to them fail.

--- FR ---

[ADD] moteur : vérificateurs d'invariants et d'indicateurs, applicatifs

Les deux vérificateurs sont livrés avec l'application et jouent à chaque
génération et à chaque fichier chargé : le premier juge un plan contre
l'instance, le second la ligne N − 1 ≥ a priori ≥ réalisé ≥ rencontres
pour chacun. Aucun ne lève sur un défaut du contenu — chaque défaut est
une violation nommée — et aucun ne modifie ce qu'il reçoit.

Vérifié : une mutation par code produit cette violation et aucune autre ;
les entrées gelées restent intactes ; trois mutants qui y écrivaient
échouent.

Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
9efcfc9973 [ADD] engine: ceilings a priori and realised, exact dynamic programme
The a priori ceiling is maximised over admissible itineraries by a dynamic
programme over tables, free rounds and capped seats, memoised by
signature, with an exhaustive enumeration as its oracle. The realised
ceiling counts the occupancy of each table at each round, not its
capacity, so a lack of zero means nothing left to take from that plan.

Checked: anchored 16 and mobile 19 on four tables of five; 28, 27, 28 and
24 on the large shape; the programme equals the enumeration on random
instances; five mutants of the formula and the programme each fail.

--- FR ---

[ADD] moteur : plafonds a priori et réalisé, programmation dynamique

Le plafond a priori se maximise sur les itinéraires admissibles par une
programmation dynamique sur les tables, les tours libres et les sièges
plafonnés, mémoïsée par signature, avec une énumération exhaustive pour
oracle. Le plafond réalisé compte l'occupation de chaque table à chaque
tour, non sa capacité : un manque nul veut dire que ce plan n'a plus rien
à reprendre.

Vérifié : ancré 16 et mobile 19 sur quatre tables de cinq ; 28, 27, 28 et
24 sur la forme de la grande ; la programmation égale l'énumération sur
des instances tirées ; cinq mutants de la formule et du calcul échouent.

Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
30045182e7 [ADD] engine: indicators measured by full recomputation
Full recomputation is the measure every displayed figure comes from
(§ 5.10). It keeps the three collision units apart — cumulative
occurrences, distinct pairs, their excess — splits table returns and
repeated meetings into those the engine chose and those the reservations
impose, and gives null, never zero, for an empty population.

Checked: the small demonstration's perfect plan gives 8 met, A = 2,
r = 6, d = 0.25 for all twelve; spread and concentrated plans give
excess 0 and 4.

--- FR ---

[ADD] moteur : indicateurs mesurés par recalcul complet

Le recalcul complet est la mesure dont sort tout chiffre affiché
(§ 5.10). Il tient séparées les trois unités de collision — occurrences
cumulées, paires distinctes, leur excédent —, partage les retours à une
table et les rencontres répétées entre ceux que le moteur a choisis et
ceux qu'imposent les réservations, et rend null, jamais zéro, pour une
population vide.

Vérifié : le plan parfait de la petite démonstration donne 8 rencontres,
A = 2, r = 6, d = 0,25 pour les douze ; plans réparti et concentré
donnent un excédent de 0 et de 4.

Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
518ef93f67 [ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.

Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.

--- FR ---

[ADD] moteur : configuration normalisée en une instance indexée

Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.

Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.

Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
cd9ea442a6 [ADD] prng: PCG32 checked against the reference C implementation
The demonstrations and the search must give the same plan from the same
seed on any machine, so every draw comes from one generator with explicit
state. PCG32 runs on 16-bit limbs without BigInt, seeded as
pcg32_srandom_r; bounded draws reject as pcg32_boundedrand_r does, and the
shuffle loop is the reference demo's. Expected values come from compiling
and running the reference implementation, never from this code.

Checked: outputs, coins, dice and deck match the reference demo; a wrong
multiplier, rotation or remainder each fail.

--- FR ---

[ADD] prng : PCG32 vérifié contre l'implémentation C de référence

Les démonstrations et la recherche doivent rendre le même plan pour la
même graine sur toute machine : chaque tirage vient d'un seul générateur à
état explicite. PCG32 calcule par mots de 16 bits sans BigInt, ensemencé
comme pcg32_srandom_r ; le tirage borné rejette comme
pcg32_boundedrand_r, et la boucle de mélange est celle de la démo de
référence. Les valeurs attendues sortent de l'implémentation de référence
compilée et exécutée, jamais de ce code.

Vérifié : sorties, pièces, dés et paquet égalent la démo de référence ;
un multiplicateur, une rotation ou un reste faussés échouent chacun.

Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
9fc104d0e9 [ADD] skeleton: Capacitor web app that shows its dated version
The engine to come must be proven against oracles under node in seconds,
so the skeleton sets three test projects: node, watched; node-long; and a
real Chromium that reads computed styles in both themes. The version
lives in version.json alone; a check refuses eight divergences — technical
form, generated module, changelog head, stray version strings — and a
build guard keeps test files and fixture assets out of the bundle.

Checked: on this commit alone, 73 node tests, 7 browser tests and the
version check pass; the guard fails on a fixture joined as an asset.

--- FR ---

[ADD] squelette : application web Capacitor qui affiche sa version datée

Le moteur à venir doit s'éprouver contre des oracles sous node en
quelques secondes : le squelette pose trois projets d'épreuve — node,
sous surveillance ; node-long ; et un vrai Chromium qui lit le style
calculé dans les deux thèmes. La version vit dans version.json seul ; un
contrôle refuse huit divergences — forme technique, module engendré,
tête du changelog, chaînes de version égarées — et une garde de
construction tient fichiers et données d'épreuve hors du paquet.

Vérifié : sur ce commit seul, 73 épreuves node, 7 navigateur et le
contrôle de version passent ; la garde échoue sur une donnée jointe.

Assisted-by: Claude Opus 5.5
2026-10-05 13:13:13 -04:00