@eqs/tooling 0.8.0 : scripts/ n'est pas publié, conformite.js ne se charge pas et eqs doctor perd TOUS les contrôles du package #44

Closed
opened 2026-09-10 03:55:23 +00:00 by nicolas-fryder · 1 comment

Constaté le 2026-09-10 en montant le premier satellite réel de @eqs/* 0.7.0 à 0.8.0. Régression de publication, pas de code : le paquet publié est incomplet.

Le symptôme

$ pnpm exec eqs doctor

eqs doctor — pilotage
  ! @eqs/tooling : @eqs/tooling/conformite n'a pas pu être chargé :
    Cannot find module '…/node_modules/@eqs/tooling/scripts/workspaces-dockerfile.js'
    imported from '…/node_modules/@eqs/tooling/conformite.js'

Aucun problème statique.
…
Échec : 1 package(s) dont les contrôles n'ont pas pu être chargés

eqs doctor sort donc en échec sur un dépôt par ailleurs sain.

La cause

conformite.js (ligne 11) fait :

import { workspacesDockerfile } from './scripts/workspaces-dockerfile.js'

Mais le dossier scripts/ n'est pas dans le paquet :

$ ls node_modules/@eqs/tooling/scripts/
ls: cannot access '…/scripts/': No such file or directory

Et le package.json publié ne le déclare pas :

"files": [
  "tsconfig.base.json", "tsconfig.nest.json", "tsconfig.next.json",
  "eslint", "prettier.json", "knip.json", "stryker.json",
  "gitleaks.json", "node.json", "orval.js", "conformite.js"
]

scripts/ manque à la liste. L'import échoue donc à l'installation, pas seulement à l'exécution du contrôle.

Pourquoi c'est plus grave que le contrôle manquant

L'import est en tête de module. Quand il échoue, ce n'est pas workspaces-dockerfile qui est indisponible : c'est @eqs/tooling/conformite en entier. Tous les contrôles du paquet disparaissent d'un coup, y compris ceux qui marchaient en 0.7.0.

Et la sortie est trompeuse dans le mauvais sens. Juste sous l'avertissement, eqs doctor affiche :

Aucun problème statique.

C'est vrai des contrôles qui ont pu se charger, mais quelqu'un qui lit vite conclut que tout va bien — alors qu'un paquet entier de contrôles n'a pas tourné. La ligne d'échec finale rattrape, mais seulement si on va jusqu'en bas.

Autrement dit : un satellite qui monte en 0.8.0 perd silencieusement une partie de sa porte, tout en voyant « aucun problème statique ».

Ce qui rend le cas particulier

Ce contrôle est né de notre ticket eqs-satellite-template#7 — le Dockerfile qui énumère les manifestes en dur, et l'installation partielle muette qui en découle. La réponse retenue était excellente et plus fine que ce que je proposais : plutôt que de figer une liste de workspaces dans le gabarit, un contrôle statique qui compare les importers du lockfile aux COPY …/package.json du Dockerfile.

Nous ne pouvons pas le vérifier : il ne se charge pas. Le défaut qu'il devait fermer reste donc ouvert en pratique pour tout satellite en 0.8.0.

Reproduction

Sur n'importe quel dépôt en @eqs/tooling 0.8.0 :

pnpm exec eqs doctor          # échoue sur le chargement
ls node_modules/@eqs/tooling/scripts/   # absent

Ce que je proposerais

Ajouter "scripts" au champ files de @eqs/tooling, et republier.

Deux garde-fous qui auraient attrapé ça, si vous les jugez utiles :

  1. Un test de fumée sur le paquet empaqueté — npm pack puis un import de chaque point d'entrée depuis le tarball extrait. C'est ce qui distingue « le code marche » de « le paquet publié marche », et c'est exactement la différence ici : le dépôt du socle est sain, seul le tarball est amputé.
  2. Faire de l'échec de chargement un bloquant explicite plutôt qu'une ligne d'avertissement suivie de « Aucun problème statique ». Un contrôle qui ne se charge pas est plus inquiétant qu'un contrôle qui échoue : on ne sait pas ce qu'on ne voit pas.

Ce qui est en place chez nous

Rien — il n'y a pas de contournement possible, et nous n'en voulons pas : ajouter le fichier à la main dans node_modules masquerait le défaut pour tout le monde. Nous restons avec eqs doctor en échec jusqu'à la republication, et nous le rejouerons dès qu'elle sera là.

À signaler si utile : le reste de la montée en 0.8.0 s'est très bien passée. Les cinq contournements que nous portions ont pu être retirés, pnpm check est vert, les 58 tests d'intégration passent, et les deux images Docker se construisent. C'est le seul point qui bloque.

Constaté le 2026-09-10 en montant le premier satellite réel de `@eqs/*` 0.7.0 à 0.8.0. **Régression de publication**, pas de code : le paquet publié est incomplet. ## Le symptôme ``` $ pnpm exec eqs doctor eqs doctor — pilotage ! @eqs/tooling : @eqs/tooling/conformite n'a pas pu être chargé : Cannot find module '…/node_modules/@eqs/tooling/scripts/workspaces-dockerfile.js' imported from '…/node_modules/@eqs/tooling/conformite.js' Aucun problème statique. … Échec : 1 package(s) dont les contrôles n'ont pas pu être chargés ``` `eqs doctor` sort donc **en échec** sur un dépôt par ailleurs sain. ## La cause `conformite.js` (ligne 11) fait : ```js import { workspacesDockerfile } from './scripts/workspaces-dockerfile.js' ``` Mais le dossier `scripts/` **n'est pas dans le paquet** : ``` $ ls node_modules/@eqs/tooling/scripts/ ls: cannot access '…/scripts/': No such file or directory ``` Et le `package.json` publié ne le déclare pas : ```json "files": [ "tsconfig.base.json", "tsconfig.nest.json", "tsconfig.next.json", "eslint", "prettier.json", "knip.json", "stryker.json", "gitleaks.json", "node.json", "orval.js", "conformite.js" ] ``` `scripts/` manque à la liste. L'import échoue donc à l'installation, pas seulement à l'exécution du contrôle. ## Pourquoi c'est plus grave que le contrôle manquant **L'import est en tête de module.** Quand il échoue, ce n'est pas `workspaces-dockerfile` qui est indisponible : c'est **`@eqs/tooling/conformite` en entier**. Tous les contrôles du paquet disparaissent d'un coup, y compris ceux qui marchaient en 0.7.0. Et la sortie est trompeuse dans le mauvais sens. Juste sous l'avertissement, `eqs doctor` affiche : ``` Aucun problème statique. ``` C'est vrai *des contrôles qui ont pu se charger*, mais quelqu'un qui lit vite conclut que tout va bien — alors qu'un paquet entier de contrôles n'a pas tourné. La ligne d'échec finale rattrape, mais seulement si on va jusqu'en bas. Autrement dit : **un satellite qui monte en 0.8.0 perd silencieusement une partie de sa porte**, tout en voyant « aucun problème statique ». ## Ce qui rend le cas particulier Ce contrôle est né de notre ticket [eqs-satellite-template#7](https://git.equilibre-structures.fr/Infrastructure/eqs-satellite-template/issues/7) — le `Dockerfile` qui énumère les manifestes en dur, et l'installation partielle muette qui en découle. La réponse retenue était excellente et plus fine que ce que je proposais : plutôt que de figer une liste de workspaces dans le gabarit, un contrôle statique qui compare les `importers` du lockfile aux `COPY …/package.json` du `Dockerfile`. **Nous ne pouvons pas le vérifier** : il ne se charge pas. Le défaut qu'il devait fermer reste donc ouvert en pratique pour tout satellite en 0.8.0. ## Reproduction Sur n'importe quel dépôt en `@eqs/tooling` 0.8.0 : ```bash pnpm exec eqs doctor # échoue sur le chargement ls node_modules/@eqs/tooling/scripts/ # absent ``` ## Ce que je proposerais Ajouter `"scripts"` au champ `files` de `@eqs/tooling`, et republier. Deux garde-fous qui auraient attrapé ça, si vous les jugez utiles : 1. **Un test de fumée sur le paquet empaqueté** — `npm pack` puis un `import` de chaque point d'entrée depuis le tarball extrait. C'est ce qui distingue « le code marche » de « le paquet publié marche », et c'est exactement la différence ici : le dépôt du socle est sain, seul le tarball est amputé. 2. **Faire de l'échec de chargement un bloquant explicite** plutôt qu'une ligne d'avertissement suivie de « Aucun problème statique ». Un contrôle qui ne se charge pas est plus inquiétant qu'un contrôle qui échoue : on ne sait pas ce qu'on ne voit pas. ## Ce qui est en place chez nous Rien — il n'y a pas de contournement possible, et nous n'en voulons pas : ajouter le fichier à la main dans `node_modules` masquerait le défaut pour tout le monde. Nous restons avec `eqs doctor` en échec jusqu'à la republication, et nous le rejouerons dès qu'elle sera là. À signaler si utile : le reste de la montée en 0.8.0 s'est très bien passée. Les cinq contournements que nous portions ont pu être retirés, `pnpm check` est vert, les 58 tests d'intégration passent, et les deux images Docker se construisent. C'est le seul point qui bloque.
nicolas-fryder referenced this issue from a commit 2026-09-10 07:04:25 +00:00
Author
Owner

Vrai de bout en bout, et c'est ma régression. @eqs/* 0.8.1 est publiée en latest.

npm pack --dry-run sur la 0.8.0 rendait 13 fichiers, aucun scripts/. Votre diagnostic était exact jusqu'au détail : l'import est en tête de module, donc ce n'est pas un contrôle qui manquait, c'est le paquet entier de contrôles qui disparaissait — y compris ceux qui marchaient en 0.7.0.

Ce qui est corrigé

Le module publié vit maintenant à la racine du paquet, avec orval.js et conformite.js. Je n'ai pas simplement ajouté "scripts" au champ files comme vous le proposiez : ça aurait aussi embarqué le vérificateur de pnpm check, qui n'a rien à faire chez un consommateur. La règle devient lisible — ce qui est publié est à la racine, scripts/ est du développement.

Votre garde-fou n°1, et il était le bon

Le check de @eqs/tooling vérifiait que chaque export existe dans l'arbre de travail, où tout est toujours là. C'est exactement pourquoi il n'a rien vu. Il éprouve désormais ce que npm pack emporte, et importe chaque point d'entrée depuis le tarball extrait.

Vérifié dans les deux sens : vert tel quel, et en retirant le fichier du champ files :

✗ export ./conformite ne s'importe pas depuis le tarball

Un détail qui a failli me faire renoncer : en déballant hors du dépôt, l'import échouait sur typescript-eslint — la dépendance, pas le fichier manquant. Un faux positif qui aurait fait désactiver la vérification. Le bac est donc déballé dans le package, où node_modules se résout en remontant.

Votre garde-fou n°2, retenu aussi

eqs doctor ne dit plus « Aucun problème statique » quand un paquet n'a pas pu se charger. Il dit « aucun problème statique parmi les contrôles qui ont pu se charger », et combien manquent. Votre formulation était juste : un contrôle qui ne se charge pas est plus inquiétant qu'un contrôle qui échoue, parce qu'on ne sait pas ce qu'on ne voit pas.

La vérification, là où le défaut vivait

J'ai rejoué votre commande sur un dépôt qui installe le paquet depuis le registre, pas depuis l'arbre de travail :

$ pnpm exec eqs doctor
eqs doctor — eqs-satellite-template
Aucun problème statique.

Sortie 0, aucune erreur de chargement. Et pour que ce ne soit pas un silence trompeur :

contrôles chargés : 5
tsconfigEtend, eslintEtend, prettierEtend, gitleaksVersion, workspacesDockerfile

Le contrôle né de votre ticket #7 est enfin exécutable chez un satellite. C'était le vrai coût de la régression : il existait, il était publié, et il ne tournait nulle part.

Puis la procédure complète — candidate sous next, portes vertes sur le socle, le gabarit et la démo, bac à sable Coolify jusqu'au service en HTTPS, promotion sans republier.

Une chose que je n'ai pas généralisée, et je préfère le dire. Les neuf autres packages publient des dossiers entiers (dist, schemas, compose) : un fichier construit y arrive tout seul. @eqs/tooling est le seul à énumérer ses fichiers, donc le seul exposé à cette faute — c'est pourquoi la vérification du tarball vit dans son check et pas dans un harnais commun aux dix. Si l'un des autres gagne un jour un dossier de premier niveau, la même faute redeviendra possible chez lui.

Merci d'avoir refusé le contournement. Ajouter le fichier à la main dans node_modules aurait masqué la régression pour tout le monde, et le contrôle serait resté muet dans les trente dépôts sans que personne le sache.

Vrai de bout en bout, et c'est ma régression. **`@eqs/*` 0.8.1 est publiée en `latest`.** `npm pack --dry-run` sur la 0.8.0 rendait 13 fichiers, aucun `scripts/`. Votre diagnostic était exact jusqu'au détail : l'import est en tête de module, donc ce n'est pas un contrôle qui manquait, c'est **le paquet entier de contrôles** qui disparaissait — y compris ceux qui marchaient en 0.7.0. **Ce qui est corrigé** Le module publié vit maintenant à la racine du paquet, avec `orval.js` et `conformite.js`. Je n'ai pas simplement ajouté `"scripts"` au champ `files` comme vous le proposiez : ça aurait aussi embarqué le vérificateur de `pnpm check`, qui n'a rien à faire chez un consommateur. La règle devient lisible — ce qui est publié est à la racine, `scripts/` est du développement. **Votre garde-fou n°1, et il était le bon** Le `check` de `@eqs/tooling` vérifiait que chaque export existe **dans l'arbre de travail**, où tout est toujours là. C'est exactement pourquoi il n'a rien vu. Il éprouve désormais ce que `npm pack` emporte, et **importe chaque point d'entrée depuis le tarball extrait**. Vérifié dans les deux sens : vert tel quel, et en retirant le fichier du champ `files` : ``` ✗ export ./conformite ne s'importe pas depuis le tarball ``` Un détail qui a failli me faire renoncer : en déballant hors du dépôt, l'import échouait sur `typescript-eslint` — la dépendance, pas le fichier manquant. Un faux positif qui aurait fait désactiver la vérification. Le bac est donc déballé **dans** le package, où `node_modules` se résout en remontant. **Votre garde-fou n°2, retenu aussi** `eqs doctor` ne dit plus « Aucun problème statique » quand un paquet n'a pas pu se charger. Il dit « aucun problème statique **parmi les contrôles qui ont pu se charger** », et combien manquent. Votre formulation était juste : un contrôle qui ne se charge pas est plus inquiétant qu'un contrôle qui échoue, parce qu'on ne sait pas ce qu'on ne voit pas. **La vérification, là où le défaut vivait** J'ai rejoué votre commande sur un dépôt qui installe le paquet **depuis le registre**, pas depuis l'arbre de travail : ``` $ pnpm exec eqs doctor eqs doctor — eqs-satellite-template Aucun problème statique. ``` Sortie 0, aucune erreur de chargement. Et pour que ce ne soit pas un silence trompeur : ``` contrôles chargés : 5 tsconfigEtend, eslintEtend, prettierEtend, gitleaksVersion, workspacesDockerfile ``` Le contrôle né de votre ticket #7 est enfin exécutable chez un satellite. C'était le vrai coût de la régression : il existait, il était publié, et il ne tournait nulle part. Puis la procédure complète — candidate sous `next`, portes vertes sur le socle, le gabarit et la démo, bac à sable Coolify jusqu'au service en HTTPS, promotion sans republier. **Une chose que je n'ai pas généralisée, et je préfère le dire.** Les neuf autres packages publient des dossiers entiers (`dist`, `schemas`, `compose`) : un fichier construit y arrive tout seul. `@eqs/tooling` est le seul à énumérer ses fichiers, donc le seul exposé à cette faute — c'est pourquoi la vérification du tarball vit dans son `check` et pas dans un harnais commun aux dix. Si l'un des autres gagne un jour un dossier de premier niveau, la même faute redeviendra possible chez lui. Merci d'avoir refusé le contournement. Ajouter le fichier à la main dans `node_modules` aurait masqué la régression pour tout le monde, et le contrôle serait resté muet dans les trente dépôts sans que personne le sache.
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#44
No description provided.