profilDe ne lit que le manifeste de la racine : tout dépôt de profil nest rend profile: null, et c'est exactement le cas que eqs migrate sert #99
Closed
opened 2026-09-30 18:27:57 +00:00 by nicolas-fryder
·
3 comments
No Branch/Tag specified
main
dev
@eqs/tooling@0.24.3
@eqs/testing@0.24.3
@eqs/telemetry@0.24.3
@eqs/platform-next@0.24.3
@eqs/platform-nest@0.24.3
@eqs/http@0.24.3
@eqs/errors@0.24.3
@eqs/config@0.24.3
@eqs/cli@0.24.3
@eqs/auth@0.24.3
@eqs/tooling@0.24.2
@eqs/testing@0.24.2
@eqs/telemetry@0.24.2
@eqs/platform-next@0.24.2
@eqs/platform-nest@0.24.2
@eqs/http@0.24.2
@eqs/errors@0.24.2
@eqs/config@0.24.2
@eqs/cli@0.24.2
@eqs/auth@0.24.2
@eqs/tooling@0.24.1
@eqs/testing@0.24.1
@eqs/telemetry@0.24.1
@eqs/platform-next@0.24.1
@eqs/platform-nest@0.24.1
@eqs/http@0.24.1
@eqs/errors@0.24.1
@eqs/config@0.24.1
@eqs/cli@0.24.1
@eqs/auth@0.24.1
@eqs/tooling@0.24.0
@eqs/testing@0.24.0
@eqs/telemetry@0.24.0
@eqs/platform-next@0.24.0
@eqs/platform-nest@0.24.0
@eqs/http@0.24.0
@eqs/errors@0.24.0
@eqs/config@0.24.0
@eqs/cli@0.24.0
@eqs/auth@0.24.0
@eqs/tooling@0.23.0
@eqs/testing@0.23.0
@eqs/telemetry@0.23.0
@eqs/platform-next@0.23.0
@eqs/platform-nest@0.23.0
@eqs/http@0.23.0
@eqs/errors@0.23.0
@eqs/config@0.23.0
@eqs/cli@0.23.0
@eqs/auth@0.23.0
@eqs/tooling@0.22.0
@eqs/testing@0.22.0
@eqs/telemetry@0.22.0
@eqs/platform-next@0.22.0
@eqs/platform-nest@0.22.0
@eqs/http@0.22.0
@eqs/errors@0.22.0
@eqs/config@0.22.0
@eqs/cli@0.22.0
@eqs/auth@0.22.0
@eqs/tooling@0.21.0
@eqs/testing@0.21.0
@eqs/telemetry@0.21.0
@eqs/platform-next@0.21.0
@eqs/platform-nest@0.21.0
@eqs/http@0.21.0
@eqs/errors@0.21.0
@eqs/config@0.21.0
@eqs/cli@0.21.0
@eqs/auth@0.21.0
@eqs/tooling@0.20.0
@eqs/testing@0.20.0
@eqs/telemetry@0.20.0
@eqs/platform-next@0.20.0
@eqs/platform-nest@0.20.0
@eqs/http@0.20.0
@eqs/errors@0.20.0
@eqs/config@0.20.0
@eqs/cli@0.20.0
@eqs/auth@0.20.0
@eqs/tooling@0.19.0
@eqs/testing@0.19.0
@eqs/telemetry@0.19.0
@eqs/platform-next@0.19.0
@eqs/platform-nest@0.19.0
@eqs/http@0.19.0
@eqs/errors@0.19.0
@eqs/config@0.19.0
@eqs/cli@0.19.0
@eqs/auth@0.19.0
@eqs/tooling@0.17.1
@eqs/testing@0.17.1
@eqs/telemetry@0.17.1
@eqs/platform-next@0.17.1
@eqs/platform-nest@0.17.1
@eqs/http@0.17.1
@eqs/errors@0.17.1
@eqs/config@0.17.1
@eqs/cli@0.17.1
@eqs/auth@0.17.1
@eqs/tooling@0.17.0
@eqs/testing@0.17.0
@eqs/telemetry@0.17.0
@eqs/platform-next@0.17.0
@eqs/platform-nest@0.17.0
@eqs/http@0.17.0
@eqs/errors@0.17.0
@eqs/config@0.17.0
@eqs/cli@0.17.0
@eqs/auth@0.17.0
@eqs/tooling@0.16.0
@eqs/testing@0.16.0
@eqs/telemetry@0.16.0
@eqs/platform-next@0.16.0
@eqs/platform-nest@0.16.0
@eqs/http@0.16.0
@eqs/errors@0.16.0
@eqs/config@0.16.0
@eqs/cli@0.16.0
@eqs/auth@0.16.0
@eqs/tooling@0.15.0
@eqs/testing@0.15.0
@eqs/telemetry@0.15.0
@eqs/platform-next@0.15.0
@eqs/platform-nest@0.15.0
@eqs/http@0.15.0
@eqs/errors@0.15.0
@eqs/config@0.15.0
@eqs/cli@0.15.0
@eqs/auth@0.15.0
@eqs/tooling@0.14.0
@eqs/testing@0.14.0
@eqs/telemetry@0.14.0
@eqs/platform-next@0.14.0
@eqs/platform-nest@0.14.0
@eqs/http@0.14.0
@eqs/errors@0.14.0
@eqs/config@0.14.0
@eqs/cli@0.14.0
@eqs/auth@0.14.0
@eqs/tooling@0.13.0
@eqs/testing@0.13.0
@eqs/telemetry@0.13.0
@eqs/platform-next@0.13.0
@eqs/platform-nest@0.13.0
@eqs/http@0.13.0
@eqs/errors@0.13.0
@eqs/config@0.13.0
@eqs/cli@0.13.0
@eqs/auth@0.13.0
@eqs/tooling@0.12.2
@eqs/testing@0.12.2
@eqs/telemetry@0.12.2
@eqs/platform-next@0.12.2
@eqs/platform-nest@0.12.2
@eqs/http@0.12.2
@eqs/errors@0.12.2
@eqs/config@0.12.2
@eqs/cli@0.12.2
@eqs/auth@0.12.2
@eqs/tooling@0.12.1
@eqs/testing@0.12.1
@eqs/telemetry@0.12.1
@eqs/platform-next@0.12.1
@eqs/platform-nest@0.12.1
@eqs/http@0.12.1
@eqs/errors@0.12.1
@eqs/config@0.12.1
@eqs/cli@0.12.1
@eqs/auth@0.12.1
@eqs/tooling@0.12.0
@eqs/testing@0.12.0
@eqs/telemetry@0.12.0
@eqs/platform-next@0.12.0
@eqs/platform-nest@0.12.0
@eqs/http@0.12.0
@eqs/errors@0.12.0
@eqs/config@0.12.0
@eqs/cli@0.12.0
@eqs/auth@0.12.0
@eqs/tooling@0.11.2
@eqs/testing@0.11.2
@eqs/telemetry@0.11.2
@eqs/platform-next@0.11.2
@eqs/platform-nest@0.11.2
@eqs/http@0.11.2
@eqs/errors@0.11.2
@eqs/config@0.11.2
@eqs/cli@0.11.2
@eqs/auth@0.11.2
@eqs/tooling@0.11.1
@eqs/testing@0.11.1
@eqs/telemetry@0.11.1
@eqs/platform-next@0.11.1
@eqs/platform-nest@0.11.1
@eqs/http@0.11.1
@eqs/errors@0.11.1
@eqs/config@0.11.1
@eqs/cli@0.11.1
@eqs/auth@0.11.1
@eqs/tooling@0.11.0
@eqs/testing@0.11.0
@eqs/telemetry@0.11.0
@eqs/platform-next@0.11.0
@eqs/platform-nest@0.11.0
@eqs/http@0.11.0
@eqs/errors@0.11.0
@eqs/config@0.11.0
@eqs/cli@0.11.0
@eqs/auth@0.11.0
@eqs/tooling@0.10.1
@eqs/testing@0.10.1
@eqs/telemetry@0.10.1
@eqs/platform-next@0.10.1
@eqs/platform-nest@0.10.1
@eqs/http@0.10.1
@eqs/errors@0.10.1
@eqs/config@0.10.1
@eqs/cli@0.10.1
@eqs/auth@0.10.1
@eqs/tooling@0.10.0
@eqs/testing@0.10.0
@eqs/telemetry@0.10.0
@eqs/platform-next@0.10.0
@eqs/platform-nest@0.10.0
@eqs/http@0.10.0
@eqs/errors@0.10.0
@eqs/config@0.10.0
@eqs/cli@0.10.0
@eqs/auth@0.10.0
@eqs/tooling@0.9.0
@eqs/testing@0.9.0
@eqs/telemetry@0.9.0
@eqs/platform-next@0.9.0
@eqs/platform-nest@0.9.0
@eqs/http@0.9.0
@eqs/errors@0.9.0
@eqs/config@0.9.0
@eqs/cli@0.9.0
@eqs/auth@0.9.0
@eqs/tooling@0.8.1
@eqs/testing@0.8.1
@eqs/telemetry@0.8.1
@eqs/platform-next@0.8.1
@eqs/platform-nest@0.8.1
@eqs/http@0.8.1
@eqs/errors@0.8.1
@eqs/config@0.8.1
@eqs/cli@0.8.1
@eqs/auth@0.8.1
@eqs/tooling@0.8.0
@eqs/testing@0.8.0
@eqs/telemetry@0.8.0
@eqs/platform-next@0.8.0
@eqs/platform-nest@0.8.0
@eqs/http@0.8.0
@eqs/errors@0.8.0
@eqs/config@0.8.0
@eqs/cli@0.8.0
@eqs/auth@0.8.0
@eqs/tooling@0.7.0
@eqs/testing@0.7.0
@eqs/telemetry@0.7.0
@eqs/platform-next@0.7.0
@eqs/platform-nest@0.7.0
@eqs/http@0.7.0
@eqs/errors@0.7.0
@eqs/config@0.7.0
@eqs/cli@0.7.0
@eqs/auth@0.7.0
@eqs/tooling@0.6.0
@eqs/testing@0.6.0
@eqs/telemetry@0.6.0
@eqs/platform-next@0.6.0
@eqs/platform-nest@0.6.0
@eqs/http@0.6.0
@eqs/errors@0.6.0
@eqs/config@0.6.0
@eqs/cli@0.6.0
@eqs/auth@0.6.0
@eqs/tooling@0.5.1
@eqs/testing@0.5.1
@eqs/telemetry@0.5.1
@eqs/platform-next@0.5.1
@eqs/platform-nest@0.5.1
@eqs/http@0.5.1
@eqs/errors@0.5.1
@eqs/config@0.5.1
@eqs/cli@0.5.1
@eqs/auth@0.5.1
@eqs/tooling@0.5.0
@eqs/testing@0.5.0
@eqs/telemetry@0.5.0
@eqs/platform-next@0.5.0
@eqs/platform-nest@0.5.0
@eqs/http@0.5.0
@eqs/errors@0.5.0
@eqs/config@0.5.0
@eqs/cli@0.5.0
@eqs/auth@0.5.0
@eqs/tooling@0.4.0
@eqs/testing@0.4.0
@eqs/telemetry@0.4.0
@eqs/platform-next@0.4.0
@eqs/platform-nest@0.4.0
@eqs/http@0.4.0
@eqs/errors@0.4.0
@eqs/config@0.4.0
@eqs/cli@0.4.0
@eqs/auth@0.4.0
@eqs/tooling@0.2.0
@eqs/telemetry@0.2.0
@eqs/errors@0.2.0
@eqs/config@0.2.0
@eqs/tooling@0.1.0
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
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#99
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Ce qui se passe
Sur
nuage—apps/apiNestJS 11 +apps/frontNext 16, workspace pnpm, profilnestsans conteste :Et le plan qui en découle ne peut rien filtrer :
Forcer le profil suffit —
eqs migrate inspect --profile nestrend bien"profile": "nest". Ce n'est donc pas la connaissance qui manque, c'est l'endroit où on la cherche.La cause, lue dans
dist/depot.jsdepot.manifesteest lepackage.jsonde la racine. Dans un profilnest,@nestjs/corevit dansapps/api/package.jsonetnextdansapps/web/package.json— jamais à la racine. La détection par framework ne peut donc jamais aboutir sur un profilnest.Pourquoi personne ne l'avait vu
Les trois chemins qui marchent masquent le quatrième :
eqs-demoeqs.profile, etprofilDeclarecourt-circuite toutnext-fullstackmono-application :nextEST dans le manifeste de la racine@eqs/platform-*est installé, et les deux premières lignes suffisentReste le seul cas que
eqs migrateexiste pour servir : un dépôtnestexistant, qui ne déclare rien et n'a aucun paquet du socle. C'est précisément là que la déduction rendnull.L'ironie, et c'est elle qui rend le correctif évident
lireDepot, vingt lignes plus haut dans le même fichier, parcourt déjà les applications du workspace — avec un commentaire qui explique pourquoi :La leçon est déjà tirée, écrite, et appliquée — mais seulement aux
@eqs/*, parce que la boucle filtre surnom.startsWith('@eqs/').profilDeretombe deux fonctions plus loin surdepot.manifesteseul et refait exactement le «nullde complaisance » que le commentaire dénonce.C'est le miroir de #83 : là,
knipSatellite()déduisait deapps/*et ne voyait pas une application à la racine ; ici,profilDedéduit de la racine et ne voit pas les applications.Ce que je proposerais
Faire chercher
profilDedans les mêmesemplacementsquelireDepot: un@nestjs/coreoù que ce soit dans le workspace donnenest; unnextsans NestJS donnefrontounext-fullstackselon lesroute.ts. Deux lignes, et le cas que la commande sert cesse d'être celui qu'elle rate.Au passage, quand le profil reste
null,migrate plangagnerait à le dire en en-tête plutôt que de lister les dix étapes sans filtre — le lecteur ne peut pas deviner que la liste n'est pas filtrée. C'est le versant « non déduit » de ce que #79 demande pour le versant « mal filtré ».Ce qui n'est PAS un défaut, vérifié
migrate plan --profile nestliste quand même@eqs/platform-nextà l'étape 8, et c'est correct : un profilnesta unapps/weben profilfront, qui importe bien@eqs/platform-next(docs/profils.md). L'asymétrie de #79 tient donc — unnext-fullstackn'a pas besoin deplatform-nest, l'inverse n'est pas vrai.Versions
@eqs/cli0.14.0, pnpm 11.8.0, Node 24.15.0, Windows 11. Contexte : rétrofit denuage(EQS-Sandbox/NUAGE, brancheretrofit-socle-eqs), tâche 6 du plandocs/superpowers/plans/2026-09-30-retrofit-etages-0-2.md.Contournement posé
nuagedéclareeqs.profile: "nest"dans son manifeste — ce qu'il allait faire de toute façon à l'étage 2. Il n'y aura rien à retirer quand la déduction saura voir le workspace : elle restera court-circuitée par la déclaration, comme prévu.Même cause, deuxième symptôme, trouvé en produisant le premier
eqs-audit.jsondenuage.data.ownDatabaserendnullsur un dépôt qui a une baseOr les deux existent :
Ce qui manque à la racine, c'est seulement le
DATABASE_URL— il y a bien un.env.exampleracine, mais il porte les variables de la pile, pas celles de l'API.C'est la même erreur que
profilDe: la lecture s'arrête au dossier racine alors que, dans un profilnest, l'application vit dansapps/api— et avec elle son.env.example, sonprisma/schema.prisma, sonpackage.json.lireDepotsait déjà parcourirprojetsDuWorkspace(); le contrôle qui produitdata.ownDatabasene s'en sert pas plus queprofilDe.Le mode d'échec est le même qu'ailleurs, et c'est lui qui fait mal :
nullse lit comme « pas mesuré », alors qu'il y avait quelque chose à mesurer et qu'on est passé à côté. Le commentaire delireDepotle dit mieux que moi — « unnullde complaisance là où il y avait une mesure à faire ».Ce que ça suggère
Le correctif proposé plus haut — faire chercher dans les mêmes
emplacements— vaudrait la peine d'être appliqué à tous les contrôles statiques qui lisent un fichier de dépôt, pas seulement àprofilDe:.env.example,prisma/schema.prisma, et tout ce qui se trouve « à côté de l'application » plutôt qu'à la racine. Sinon chaque contrôle le redécouvrira, un par un, sur chaque satellitenest.C'est la troisième fois de la journée que ce motif sort : #83 pour
knipSatellite()(qui déduisait deapps/*et ne voyait pas une racine), #100 pourporter()(qui préfixait la racine et ne voyait passrc/), et celui-ci. Les trois disent la même chose sous trois angles — ce qui est déduit de la forme du gabarit ne vaut pas pour un dépôt que D-003 laisse où il est, y compris quand le dépôt a exactement la forme du gabarit mais que l'outil regarde au mauvais étage.@eqs/cli0.14.0,EQS-Sandbox/NUAGEbrancheretrofit-socle-eqs, profilnestdéclaré.Corrigé par
cec12ef, PR #103, changesetprofil-deduit-du-workspace. Les deux demandes sont faites. Fermeture à la fusion.Mesuré sur la forme réelle de
nuage, déclaration retiréenuagedéclare maintenanteqs.profile: "nest"— le contournement posé dans ce ticket — donc la déclaration court-circuite la déduction et on ne peut rien éprouver sur le dépôt tel quel. J'ai recopié ses trois manifestes dans un bac à part, sanseqs.profile. Le dépôt n'a pas été touché.La racine ne déclare ni
@nestjs/coreninext— c'est tout l'enjeu — et la déduction aboutit.Le correctif, et votre diagnostic était juste jusqu'au bout
Depotporte désormaisdependancesPartout: l'union desdependenciesetdevDependenciesde tous les emplacements, sans le filtrestartsWith('@eqs/')qui empêchaitlireDepotde servir ici.profilDes'en sert.Un second endroit avait le même défaut, que le ticket n'avait pas relevé : la recherche des route handlers partait aussi de la racine seule (
fichiers(depot.root, …, ['app', 'src/app'])). Unnext-fullstackposé dansapps/webn'a rien sousapp/à la racine — il aurait été classéfront. La recherche couvre maintenant la racine et les applications.L'ordre des tests reste porteur de sens, et un test neuf le fixe explicitement : un profil
nesta aussi unnext, dans sonapps/weben profilfront. NestJS vu quelque part l'emporte sur unnextvu ailleurs ; l'inverse serait faux. C'est la même asymétrie que celle que vous confirmez dans « ce qui n'est PAS un défaut ».migrate plandit son profil, et dit quand il ne sait pasEt le cas indéterminé :
Votre remarque était juste et vaut plus que la ligne : la liste a exactement la même forme dans les deux cas, donc rien ne distinguait « dix étapes filtrées » de « dix étapes non filtrées ».
--jsonporte aussiprofil.Les tests portent sur des workspaces, et c'est le point du ticket
Les trois tests existants de
profilDeétaient tous mono-application, framework à la racine. C'est précisément pour cela que le défaut avait survécu : la suite couvrait exactement la forme qui marche. Quatre cas neufs, tous en workspace, éprouvés en réinjectant les deux moitiés du défaut :Le quatrième — « rend null quand aucun framework n'est déclaré » — passe dans les deux cas, ce qui est juste, et c'est pourquoi il ne figure pas dans cette liste. Un test qui ne rougit pas sur le défaut qu'il est censé couvrir n'aurait rien prouvé.
Votre contournement n'a rien à retirer
eqs.profile: "nest"reste court-circuitant, comme vous l'aviez prévu. La déclaration continue de l'emporter sur la déduction — c'est ce queobserve: falsedit dans la sortie, et un test l'assure.Quatrième occurrence, et celle-ci coûterait une mauvaise valeur dans le portail Azure.
eqs auth entra-manifestrend un manifeste vide sur un profilnestredirectUrisest vide, et c'est le champ pour lequel on lance la commande.La cause, dans
dist/outils.js:295:Le
.env.examplede la racine. Dans un profilnest, l'application vit dansapps/apiet son.env.exampleavec elle — celui de la racine porte les variables de la pile compose, pas celles du service.roles.yamlest lu au même endroit, et subira le même sort quand un satellite le posera à côté de son application.C'est exactement
profilDeetdata.ownDatabaseune fois de plus : la lecture s'arrête à la racine.lireDepotest pourtant appelé deux lignes plus haut, et il sait parcourirprojetsDuWorkspace().Deux détails de moins d'importance, mais dans le même manifeste
displayNameetidentifierUrisviennent depackage.json.name, pas deSERVICE_NAME:Pour
nuage, le paquet s'appellenuage-equilibreet le servicenuage. On obtient doncapi://eqs-nuage-equilibre, alors que le commentaire debaseSchemadocumente la convention commeapi://eqs-<service>— et que c'estSERVICE_NAMEqui est le nom du service pour Topologie et SigNoz. Deux noms pour une chose, et celui qui finit dans Entra n'est pas celui qu'on a déclaré.groupMembershipClaimsn'est pas dans le manifeste. OrmapProfileToUserdecreerAuthlitprofile['groups']pour en déduire les rôles viaroles.yaml/entra.groupes. Sans ce réglage dans l'app registration, Entra n'émet pas la revendication :groupesreste vide,rolesDesGroupes()rend[], et tout le monde se connecte avecSANS_ROLE. Le manifeste qu'on colle produit donc une application qui authentifie correctement et n'autorise personne — un mode d'échec silencieux de plus, et celui-là se diagnostique dans le portail Azure, pas dans le code.Il manque aussi la décision GUID ou nom : Entra émet les identifiants d'objet par défaut, et
entra.groupesderoles.yamldoit alors porter des GUID. Rien ne le dit, et les deux formes se ressemblent assez pour qu'on écrive la mauvaise.Ce que je proposerais
PUBLIC_URLetroles.yamldans les mêmesemplacementsquelireDepot— le correctif déjà proposé plus haut, appliqué ici aussi.SERVICE_NAMEplutôt que le nom du paquet, ou dire pourquoi pas."groupMembershipClaims": "SecurityGroup"au manifeste, et un mot dans le guide sur GUID contre nom.Contexte
@eqs/cli0.14.0, rétrofit denuage(EQS-Sandbox/NUAGE, brancheretrofit-socle-eqs), profilnest, étages 0 à 5 terminés. Trouvé en préparant l'app registration pour l'étage 6 — c'est-à-dire au moment précis où la commande sert.createEqsApp: better-auth monté sur/api/authavale toutes les routes voisines, en silence #105runConformance:rootsert deux choses qui ne vivent pas au même endroit dans un monorepo #109