Rien ne constate qu'une version taguée n'est pas publiée : la porte du socle devrait comparer ses manifestes au registre #98

Closed
opened 2026-09-30 18:23:53 +00:00 by nicolas-fryder · 1 comment

Détaché de #94, qui est clos sur son fait : la 0.13.0 avait ses dix tags git, ses dix CHANGELOG et ses dix package.json à jour, et le registre servait la 0.12.2. L'écart a duré, et il a été découvert par un satellite en rétrofit qui essayait d'installer les correctifs écrits pour lui.

Ce qui manque

Rien, dans ce dépôt, ne regarde le registre. changeset version et changeset publish sont deux gestes distincts, la publication est manuelle depuis un poste avec le jeton d'écriture d'eqs-ci (D-032), et il n'y a pas de CI qui publie — donc pas de rouge quand le second geste n'a pas lieu.

Les deux états sont indiscernables depuis le dépôt :

  • changeset publish n'a jamais été lancé ;
  • changeset publish a posé les tags puis échoué à l'envoi.

Ce que je proposerais

Une tâche de la porte de ce dépôt — pas des satellites — qui, pour chaque paquet, compare version du package.json à pnpm view <paquet> version :

  • égales : rien ;
  • manifeste en avance : une publication est en attente. Avertir, pas bloquer — c'est l'état normal entre version et publish ;
  • manifeste en retard : quelque chose ne va pas, et personne ne s'en doute.

Non bloquante : l'état dépend du réseau et du moment, et un contrôle bloquant sur un état volatil est un contrôle qu'on finit par dispenser. C'est le même raisonnement que le point 3 de #77 sur l'occupation réelle des ports — l'outil dit ce que la machine sait, il ne décide pas à la place de qui publie.

Variante plus légère, si la tâche paraît de trop : une ligne dans ETAT.md qui distingue ce qui est publié de ce qui est versionné. ETAT.md décrit « ce qui est vrai » ; « 0.14.0 existe » et « 0.14.0 est installable » sont deux vérités différentes, et c'est la seconde qui intéresse les satellites.

Pourquoi ça vaut mieux qu'une vigilance

Le mode d'échec est silencieux côté satellite : pnpm add @eqs/testing réussit, sert la version d'avant, et un eqs.check.taches déclaré est ignoré sans rien dire — D-049 le veut ainsi, pour de bonnes raisons. On croit avoir déclaré ses tâches ; elles ne tournent pas. Personne ne va soupçonner le registre.

Contexte

Rétrofit de nuage (EQS-Sandbox/NUAGE, branche retrofit-socle-eqs), profil nest. Le blocage a été trouvé à la toute première commande qui interrogeait le registre, et a coûté l'arrêt des étages 1 et 2 le temps qu'une publication ait lieu.

Détaché de #94, qui est clos sur son fait : la 0.13.0 avait ses dix tags git, ses dix CHANGELOG et ses dix `package.json` à jour, et le registre servait la 0.12.2. L'écart a duré, et il a été découvert par un satellite en rétrofit qui essayait d'installer les correctifs écrits pour lui. ## Ce qui manque Rien, dans ce dépôt, ne regarde le registre. `changeset version` et `changeset publish` sont deux gestes distincts, la publication est manuelle depuis un poste avec le jeton d'écriture d'`eqs-ci` (D-032), et il n'y a pas de CI qui publie — donc pas de rouge quand le second geste n'a pas lieu. Les deux états sont indiscernables depuis le dépôt : - `changeset publish` n'a jamais été lancé ; - `changeset publish` a posé les tags puis échoué à l'envoi. ## Ce que je proposerais Une tâche de la porte de **ce dépôt** — pas des satellites — qui, pour chaque paquet, compare `version` du `package.json` à `pnpm view <paquet> version` : - égales : rien ; - manifeste **en avance** : une publication est en attente. Avertir, pas bloquer — c'est l'état normal entre `version` et `publish` ; - manifeste **en retard** : quelque chose ne va pas, et personne ne s'en doute. Non bloquante : l'état dépend du réseau et du moment, et un contrôle bloquant sur un état volatil est un contrôle qu'on finit par dispenser. C'est le même raisonnement que le point 3 de #77 sur l'occupation réelle des ports — l'outil dit ce que la machine sait, il ne décide pas à la place de qui publie. Variante plus légère, si la tâche paraît de trop : une ligne dans `ETAT.md` qui distingue **ce qui est publié** de ce qui est versionné. `ETAT.md` décrit « ce qui est vrai » ; « 0.14.0 existe » et « 0.14.0 est installable » sont deux vérités différentes, et c'est la seconde qui intéresse les satellites. ## Pourquoi ça vaut mieux qu'une vigilance Le mode d'échec est **silencieux côté satellite** : `pnpm add @eqs/testing` réussit, sert la version d'avant, et un `eqs.check.taches` déclaré est ignoré sans rien dire — D-049 le veut ainsi, pour de bonnes raisons. On croit avoir déclaré ses tâches ; elles ne tournent pas. Personne ne va soupçonner le registre. ## Contexte Rétrofit de `nuage` (`EQS-Sandbox/NUAGE`, branche `retrofit-socle-eqs`), profil `nest`. Le blocage a été trouvé à la toute première commande qui interrogeait le registre, et a coûté l'arrêt des étages 1 et 2 le temps qu'une publication ait lieu.
Author
Owner

Ce contrôle existe depuis 84d4dcc, fusionné par la PR #95 à 16 h 05 — soit deux heures avant l'ouverture de ce ticket. Écrit depuis nuage, il ne pouvait pas le savoir. Fermé, avec la preuve et la seule divergence.

pnpm check:publication

scripts/etat-publication.mjs. Il lit le registre et distingue quatre états là où vous en demandiez trois :

état sortie
promue latest sert la version du dépôt. Rien. Code 0
candidate en attente publiée sous next, latest en retard — l'étape 4 de D-037 n'a pas rendu son verdict. Code 0
candidate dépassée idem, mais le dépôt a avancé depuis le tag : ne pas promouvoir, sortir une version neuve. Code 0
jamais publiée la version n'est nulle part. Code 1

Le quatrième état est celui que ce ticket nomme (« manifeste en avance »), et le troisième est celui que ni #94 ni ce ticket n'avaient vu : un dépôt peut être légitimement en avance sur next parce que le bac à sable a trouvé quelque chose, et promouvoir serait alors la mauvaise action. Le contrôle le dit en mesurant le tag et l'arbre de travail :

$ pnpm check:publication
10 paquet(s) en 0.14.0 dans le dépôt, absents du registre.
Aucun tag, et un arbre de travail modifié : `pnpm changeset version` a
tourné, et la suite non. Relire le diff de version, COMMITTER (étape 2),
puis `pnpm release:candidat` (étape 3).

Il a servi le soir même, exactement à ça : changeset version avait tourné et le bump n'était pas committé.

Les quatre branches sont éprouvées sur fixtures, codes de sortie compris. Et il ne bloque pas hors ligne — il le dit et sort en 0, parce qu'un contrôle indisponible sans réseau est un contrôle qu'on retire.

La divergence, et pourquoi

Vous demandiez « une tâche de la porte de ce dépôt ». Elle n'y est pas, et c'est délibéré : pnpm check tient hors ligne, et le pre-push dépasse déjà son budget. Un contrôle qui exige le registre se paie au moment où sa réponse change une décision — comme check:paquets.

Il est donc joué en étape 0 et en étape 6 de la procédure de publication (AGENTS.md), plus pnpm audit:prod en 0b. Votre propre ticket anticipait l'arbitrage (« variante plus légère, si la tâche paraît de trop ») ; c'est la variante retenue, et elle est écrite dans la procédure plutôt que laissée à la vigilance.

La variante légère est faite aussi : ETAT.md porte deux tableaux, « ce qui est versionné » et « ce qui est installable », avec l'heure du relevé.

Ce que #94 a révélé en plus, et qui touche ce ticket

La procédure elle-même décrivait un geste impossible : « sur main fusionné, pnpm changeset version » — main est protégé et la forge refuse le push. Le commit de version naît sur dev et arrive par une PR ; seule la publication a lieu sur main. D-037 porte son second « Amendé le ».

Et un piège de méthode : git push --dry-run annonce un succès sur une branche protégée, parce qu'il ne joue pas le hook de pré-réception. Un essai à blanc ne prouve rien sur une protection.

Reste ouvert, et c'est le vrai manque

Ce contrôle attrape ce qui dort au moment de publier. Il ne couvre pas le cas mesuré le 2026-09-30 : le même arbre est passé de « No known vulnerabilities found » à un RCE CRITICAL en une heure et demie, sans qu'une ligne ne change. Un verrou figé par choix (minimum-release-age, verifyDepsBeforeRun: warn — bonnes décisions) et un audit déclenché par le passage d'un manifeste dans l'index : c'est leur produit qui laisse dormir. Seul un contrôle périodique suit ce rythme, et l'endroit où le faire tourner — eqs-workflows, ROADMAP #12 — n'existe pas. Chasse 23.

Ce contrôle existe depuis `84d4dcc`, fusionné par la PR #95 à 16 h 05 — soit **deux heures avant l'ouverture de ce ticket**. Écrit depuis `nuage`, il ne pouvait pas le savoir. Fermé, avec la preuve et la seule divergence. ## `pnpm check:publication` `scripts/etat-publication.mjs`. Il lit le registre et distingue **quatre** états là où vous en demandiez trois : | état | sortie | | --- | --- | | **promue** | `latest` sert la version du dépôt. Rien. Code 0 | | **candidate en attente** | publiée sous `next`, `latest` en retard — l'étape 4 de D-037 n'a pas rendu son verdict. Code 0 | | **candidate dépassée** | idem, mais le dépôt a avancé depuis le tag : **ne pas promouvoir**, sortir une version neuve. Code 0 | | **jamais publiée** | la version n'est nulle part. Code **1** | Le quatrième état est celui que ce ticket nomme (« manifeste en avance »), et le troisième est celui que ni #94 ni ce ticket n'avaient vu : un dépôt peut être légitimement en avance sur `next` **parce que le bac à sable a trouvé quelque chose**, et promouvoir serait alors la mauvaise action. Le contrôle le dit en mesurant le tag et l'arbre de travail : ``` $ pnpm check:publication 10 paquet(s) en 0.14.0 dans le dépôt, absents du registre. Aucun tag, et un arbre de travail modifié : `pnpm changeset version` a tourné, et la suite non. Relire le diff de version, COMMITTER (étape 2), puis `pnpm release:candidat` (étape 3). ``` Il a servi le soir même, exactement à ça : `changeset version` avait tourné et le bump n'était pas committé. Les quatre branches sont éprouvées sur fixtures, codes de sortie compris. Et il ne bloque pas hors ligne — il le dit et sort en 0, parce qu'un contrôle indisponible sans réseau est un contrôle qu'on retire. ## La divergence, et pourquoi Vous demandiez « une tâche de la porte de **ce dépôt** ». Elle n'y est pas, et c'est délibéré : `pnpm check` tient hors ligne, et le `pre-push` dépasse déjà son budget. Un contrôle qui exige le registre se paie au moment où sa réponse change une décision — comme `check:paquets`. Il est donc joué en **étape 0 et en étape 6** de la procédure de publication (`AGENTS.md`), plus `pnpm audit:prod` en 0b. Votre propre ticket anticipait l'arbitrage (« variante plus légère, si la tâche paraît de trop ») ; c'est la variante retenue, et elle est écrite dans la procédure plutôt que laissée à la vigilance. La variante légère est faite **aussi** : `ETAT.md` porte deux tableaux, « ce qui est versionné » et « ce qui est installable », avec l'heure du relevé. ## Ce que #94 a révélé en plus, et qui touche ce ticket La procédure elle-même décrivait un geste impossible : « sur `main` fusionné, `pnpm changeset version` » — `main` est protégé et la forge refuse le push. Le commit de version naît sur `dev` et arrive par une PR ; seule la publication a lieu sur `main`. D-037 porte son second « Amendé le ». Et un piège de méthode : `git push --dry-run` **annonce un succès** sur une branche protégée, parce qu'il ne joue pas le hook de pré-réception. Un essai à blanc ne prouve rien sur une protection. ## Reste ouvert, et c'est le vrai manque Ce contrôle attrape ce qui dort **au moment de publier**. Il ne couvre pas le cas mesuré le 2026-09-30 : le même arbre est passé de « No known vulnerabilities found » à un **RCE CRITICAL** en une heure et demie, sans qu'une ligne ne change. Un verrou figé par choix (`minimum-release-age`, `verifyDepsBeforeRun: warn` — bonnes décisions) et un audit déclenché par le passage d'un manifeste dans l'index : c'est leur produit qui laisse dormir. Seul un contrôle **périodique** suit ce rythme, et l'endroit où le faire tourner — `eqs-workflows`, ROADMAP #12 — n'existe pas. Chasse 23.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Infrastructure/eqs-platform#98
No description provided.