La règle de clé d'un fichier portable a changé : seule la fin du chemin compte
désormais. Les objets écrits sous l'ancienne règle restent sur le disque mais
deviennent introuvables — le service les redemande à l'amont, et la place
qu'ils tiennent ne sert plus personne. Sur un magasin de 12 764 objets, 5 419
étaient dans ce cas, soit 9,11 Gio. La passe les range sous la clé courante
sans rien retélécharger, et fond au passage les copies qu'un miroir portait
sous plusieurs chemins — 1 422 groupes, environ 3,37 Gio rendus. Un statut
seul n'est pas touché : sa clé porte l'hôte. Vérifié : cinq tests, trois
mutations attrapées.
--- EN ---
The key rule for a portable file changed: only the end of the path now counts.
Objects written under the old rule stay on disk but become unreachable — the
service asks upstream again, and the space they hold serves no one. On a store
of 12 764 objects, 5 419 were in that case, that is 9.11 GiB. The pass stores
them again under the current key without downloading anything, and merges on
the way the copies a mirror carried under several paths — 1 422 groups, about
3.37 GiB returned. A status-only entry is left alone: its key carries the
host. Checked: five tests, three mutations caught.
Assisted-by: Claude Opus 5
Rien n'invalidait une entrée dont la somme ne correspond pas : le magasin
continuait de la servir, et retélécharger ne changeait rien puisque c'est
lui qui répond. Les deux purges existantes ne l'atteignent pas — l'une
efface tout, l'autre saute ce qui est récent alors que chaque service
remet cette date, si bien qu'un objet empoisonné qui sert ne vieillit
jamais.
Symétrique de « --detient » : mêmes lignes, mêmes fonctions de clé, mêmes
refus, et un objet présent qui résiste est dit refusé plutôt qu'oublié.
Mesuré : garde, puis oublié 53080, puis absent.
--- EN ---
Nothing invalidated an entry whose checksum does not match: the store kept
serving it, and re-downloading changed nothing since the store is what
answers. Neither existing purge reaches it — one erases everything, the
other skips what is recent while every service resets that date, so a
poisoned object that serves never ages.
Symmetric to "--detient": same lines, same key functions, same refusals,
and a present object that resists is reported refused rather than
forgotten. Measured: held, then forgotten 53080, then absent.
Assisted-by: Claude Opus 5
Les tests longs lançaient la CLI sans privilège, alors que le dossier des
images appartient à root en 755 : arrêt à l'étape 1 sur « Permission
refusée », avant d'avoir rien créé. Ils ne pouvaient donc pas tourner du
tout — pas même échouer utilement. Le menu passe sudo depuis toujours ;
c'est cette forme qui est reprise, et jamais à blanc.
Le refus de place d'un miroir reprenait un champ que tout appelant laisse
à zéro : « moins de 0 o libres » n'annonce aucun seuil et ne dit pas ce
qui a été mesuré. Treize tests héritaient du plancher de production,
10 Gio, et rougissaient sur un /tmp en tmpfs.
--- EN ---
The long tests ran the CLI unprivileged, while the image directory is
owned by root, mode 755: they stopped at step 1 on "permission denied",
before creating anything. They therefore could not run at all — not even
fail usefully. The menu has always passed sudo; that is the form taken
here, and never on a dry run.
A mirror's refusal for lack of space echoed a field every caller leaves at
zero: "less than 0 B free" announces no threshold and does not say what
was measured. Thirteen tests inherited the production floor, 10 GiB, and
went red on a tmpfs /tmp.
Assisted-by: Claude Opus 5
A package manager opens several connections to one repository at once and
closes those it does not use. The cache saw three cut handshakes in the same
second, counted three refusals, and moved the host to an opaque tunnel, which
never consults the store. A client then waited four hours on that tunnel,
holding a socket the far end had closed, until its own deadline killed it.
Cuts closer than two seconds now count as one incident; a client that really
rejects the authority retries seconds later and is banned as before. A closing
tunnel is logged with its duration and bytes each way.
--- FR ---
Un gestionnaire de paquets ouvre plusieurs connexions de front vers un dépôt
et ferme celles dont il ne se sert pas. Le cache voyait trois poignées de main
coupées dans la même seconde, comptait trois refus, et passait l'hôte en
tunnel opaque, qui ne consulte jamais le magasin. Un client attendait alors
quatre heures sur ce tunnel, sur un socket que l'autre bout avait refermé,
jusqu'à son propre délai. Deux coupures à moins de deux secondes comptent
désormais pour un incident ; un client qui rejette vraiment l'autorité
réessaie et reste condamné. La fin d'un tunnel est journalisée.
Assisted-by: Claude Opus 5
Le cache ne diminuait jamais de lui-même et vit sur le disque de
l'orchestrateur : un parc qui déploie chaque jour finissait par le remplir,
sans que rien ne le signale. Deux règles existent désormais, éteintes par
défaut et réglées depuis le menu : l'âge du dernier usage, et un plafond de
taille qui efface le moins récemment servi jusqu'à tenir dessous, objets et
dépôts git confondus. Un minuteur systemd quotidien les applique, et une
réinstallation garde les valeurs choisies. Le menu montre d'abord ce qui
partirait.
--- EN ---
The cache never shrank by itself and lives on the orchestrator's disk: a site
deploying every day filled it up with nothing to say so. Two rules now exist,
off by default and set from the menu: the age of last use, and a size ceiling
that erases the least recently served until the cache fits under it, objects
and git mirrors alike. A daily systemd timer applies them, and a reinstall
keeps the chosen values. The menu first shows what would go.
Assisted-by: Claude Opus 5
Sur une installation complète, les index pip, les métadonnées npm et le
bundle de repo pesaient environ 110 Mo par VM, repris en entier à chaque
fois. Un index déjà gardé part désormais avec son ETag : l'amont juge chaque
requête, et un « 304 » sert le corps depuis le disque. Sous « Vary: Accept »,
chaque représentation est rangée à part, faute de quoi deux clients qui
alternent les retéléchargent tour à tour. Les métadonnées PEP 658 de pip,
nommées « .whl.metadata », sont figées comme l'archive qu'elles décrivent.
--- EN ---
On a full install the pip indexes, npm metadata and repo bundle weighed about
110 MB per VM, taken whole every time. An index already kept now leaves with
its ETag: upstream judges every request, and a « 304 » serves the body from
disk. Under « Vary: Accept » each representation is stored apart, without
which two clients alternating between them re-download each in turn. The
PEP 658 metadata of pip, named « .whl.metadata », are as immutable as the
archive they describe.
Assisted-by: Claude Opus 5
Le binaire ne parlait que français alors que le menu suit EL_LANG : un
opérateur anglophone lisait un statut qu'il ne comprenait pas. Chaque message
humain passe par T(), dont la clé EST le texte français, et un catalogue
anglais le traduit ; la langue vient de --lang, puis d'EL_LANG, le français
restant le défaut. Le menu demande le français pour ce qu'il RELIT, ses
motifs ne connaissant que cette langue. Un test refuse un message sans
traduction, une traduction orpheline et un verbe de format qui diverge.
--- EN ---
The binary spoke French only while the menu follows EL_LANG: an English
reader got a status he could not read. Every human message goes through T(),
whose key IS the French text, and an English catalogue translates it; the
language comes from --lang, then EL_LANG, French remaining the default. The
menu asks for French for what it READS BACK, its patterns knowing that
language alone. A test refuses a message without translation, an orphan
translation, and a format verb that drifts.
Assisted-by: Claude Opus 5