[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CSVQNDCYWX9XYRFS71RKYZ":3,"skill-same:01M6CSVQNDCYWX9XYRFS71RKYZ":143},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":98,"commitSha":99,"skillDirectory":100,"forksCount":14,"repositoryHtmlUrl":101,"repositoryHomepageUrl":6,"ownerHtmlUrl":102,"ownerBlogUrl":6,"ownerDescription":103,"updatedAt":104,"install":105,"resources":118},"01M6CSVQNDCYWX9XYRFS71RKYZ","volontariapp-shared-npm-package-change",null,"Modifier un package partagé de npm-packages (messaging, shared, database, domain-*, auth...) et propager la nouvelle version aux consommateurs : rayon d'impact, build, changeset, STOP, snapshot CI, yarn up. À utiliser avant toute édition sous npm-packages\u002Fpackages\u002F.","Volontariapp\u002Fmeta","Volontariapp","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F263673138?v=4","01M6CSQNQ3J4SKRWA512JQF5K7","VolontariApp","01M6CSQNV8T2M4PR5A22DKHY5T",0,"MIT","https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-shared-npm-package-change\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"npm package","package","change","npm","volontariapp shared npm package change","shared","impact","snap","code","workflows","database","ci","up","pipeline","auth","changeset","changesets","messaging","npm-packages","orchestrate","2026-11-10 10:12:30",false,"---\nname: volontariapp-shared-npm-package-change\ndescription: \"Modifier un package partagé de npm-packages (messaging, shared, database, domain-*, auth...) et propager la nouvelle version aux consommateurs : rayon d'impact, build, changeset, STOP, snapshot CI, yarn up. À utiliser avant toute édition sous npm-packages\u002Fpackages\u002F.\"\ntype: Agent Skill\ntitle: Shared NPM Package Change\ntags: [npm-packages, changesets, stop-rule]\nstatus: stable\npaths:\n  - npm-packages\u002Fpackage.json\n  - \"npm-packages\u002Fpackages\u002F*\u002Fpackage.json\"\n  - \"npm-packages\u002Fpackages\u002F*\u002FCHANGELOG.md\"\n  - npm-packages\u002Fyarn.lock\n  - npm-packages\u002F.changeset\u002Fconfig.json\n  - \"npm-packages\u002F.github\u002Fworkflows\u002F**\"\nmesh_keys:\n  - npm-packages\n  - \"@volontariapp\u002F\"\ngenerated:\n  by: claude-code\u002Fclaude-opus-5-5\n  at: \"2026-10-06T08:22:12Z\"\nsources:\n  - id: changeset\n    resource: npm-packages\u002F.changeset\u002Fconfig.json\n    title: Configuration changesets\n  - id: npm-ci\n    resource: npm-packages\u002F.github\u002Fworkflows\n    title: CI de publication npm-packages\n  - id: orchestrate\n    resource: npm-packages\u002Fscripts\u002Fci-orchestrate.py\n    title: \"ci-orchestrate.py (plan, version snapshot)\"\n  - id: snap\n    resource: npm-packages\u002Fscripts\u002Fci-snap-publish.sh\n    title: ci-snap-publish.sh (dist-tag next)\n  - id: pipeline\n    resource: ci-tools\u002F.github\u002Fworkflows\u002Fnpm-packages-pipeline.yml\n    title: Pipeline réutilisable npm-packages (ci-tools)\nverified:\n  - by: claude-code\u002Fagent\n    at: \"2026-11-02T11:07:22Z\"\n    digest: a449048c4609013e\n  - by: claude-code\u002Fagent\n    at: \"2026-11-04T21:25:07Z\"\n    digest: 84e8022a76347fbe\n  - by: claude-code\u002Fagent\n    at: \"2026-11-08T11:53:22Z\"\n    digest: 292021b063207bff\n  - by: claude-code\u002Fagent\n    at: \"2026-11-08T12:07:09Z\"\n    digest: 94f91136a88eb724\n  - by: claude-code\u002Fagent\n    at: \"2026-11-08T22:50:47Z\"\n    digest: 94f91136a88eb724\n---\n\n# Shared NPM Package Change & Règle d'Or du Stop Immédiat\n\nLe répertoire `npm-packages\u002Fpackages\u002F` contient l'ensemble du code partagé entre microservices et leurs processus satellites :\n- **Packages de domaine (`domain-\u003Cdomaine>`)** : partagés entre `ms-\u003Cdomaine>`, `outbox-\u003Cdomaine>`, `worker-\u003Cdomaine>` et `post-processors-runner`.\n- **Packages transverses (`messaging`, `contracts`, `database`, `auth`, `logger`, `errors`, `monitoring`)** : consommés par l'ensemble des 17 dépôts.\n\n---\n\n## 🛑 RÈGLE D'OR ABSOLUE : LE STOP IMMÉDIAT\n\n> [!CAUTION]\n> **DÈS QUE TU AS TERMINÉ DE MODIFIER QUOI QUE CE SOIT DANS `npm-packages` :**\n> 1. Tu vérifies localement la compilation : `yarn build` (et `yarn test`).\n> 2. Tu crées le changeset puis tu appliques le bump : `yarn changeset add` puis `yarn changeset version` (une seule fois par branche).\n> 3. **TU T'ARRÊTES IMMÉDIATEMENT**. Tu ne touches à AUCUN autre fichier ou repository.\n> 4. **INTERDICTION FORMELLE** d'aller modifier, tester ou compiler les microservices consommateurs (`ms-*`, `api-gateway`, runners) en avance.\n> 5. **INTERDICTION FORMELLE** de bricoler des types, d'utiliser du casting `as unknown as Type`, ou de poser du `any` pour faire semblant que le code compile sans le paquet publié.\n> 6. **ACTION EXIGÉE** : Tu passes la main au Lead Dev. Tu lui indiques que les modifications dans `npm-packages` sont prêtes et tu **ATTENDS qu'il pousse sur une PR**.\n> 7. La CI GitHub Actions s'exécute sur la PR et génère une version snapshot `\u003Cversion>-snap-\u003Csha court>`, publiée sous le dist-tag `next` et listée en commentaire de la PR (ex: `@volontariapp\u002Fmessaging@2.17.1-snap-a1b2c3d`) ou définitive sur `main`.\n> 8. **Ce n'est qu'APRÈS la publication effective par la CI** que tu pourras mettre à jour les dépendances dans les microservices consommateurs (`yarn up @volontariapp\u002F\u003Cpkg>@\u003Cversion>`).\n\n---\n\n## 1. Avant de modifier un package partagé (Impact Analysis)\n\nNe jamais modifier un package à l'aveugle :\n1. **Mesurer le rayon d'impact** : Utilise l'outil MCP `find_dependents` pour identifier en $O(1)$ tous les fichiers et services qui importent le package ou symbole modifié :\n   ```json\n   find_dependents({ \"target\": \"@volontariapp\u002Fmessaging\" })\n   find_dependents({ \"target\": \"SignUpCommand\" })\n   ```\n2. **Pour les flux asynchrones** : Si tu modifies un événement ou un job dans `messaging`, utilise l'outil MCP `analyze_impact` pour visualiser les producteurs, consommateurs et sagas impactés :\n   ```json\n   analyze_impact({ \"target\": \"USER_CREATED\" })\n   ```\n\n---\n\n## 2. Déroulement du Workflow Pas-à-Pas\n\n```mermaid\nflowchart TD\n    A[\"1. Édition du code dans npm-packages\u002F\"] --> B[\"2. Validation locale (yarn build & yarn test)\"]\n    B --> C[\"3. Changeset et bump (yarn changeset add puis version)\"]\n    C --> D[\"🛑 4. STOP IMMÉDIAT (Passage de main au Lead Dev)\"]\n    D --> E[\"5. Le Lead Dev push sur PR GitHub\"]\n    E --> F[\"6. La CI publie la version Snapshot \u002F Release\"]\n    F --> G[\"7. Reprise : yarn up dans les microservices consommateurs\"]\n```\n\n1. **Édition locale** : Modifications ciblées dans `npm-packages\u002Fpackages\u002F\u003Cpackage>`.\n2. **Build & Tests** : Vérifier que `yarn build` passe sans aucune erreur.\n3. **Changeset** :\n   - Exécuter `yarn changeset add` et sélectionner les packages modifiés, puis `yarn changeset version` pour écrire la version et le `CHANGELOG.md` que la CI vérifie.\n   - Ne JAMAIS bumper deux fois le même package sur la même branche (ex: pas de 3.1 -> 3.3). Avant `version`, comparer `package.json` à `origin\u002Fmain` : s'il est déjà différent, le bump a eu lieu.\n   - `yarn changeset add` est interactif. Sans TTY, écrire `.changeset\u002F\u003Cnom>.md` (en-tête `'@volontariapp\u002F\u003Cpkg>': minor|patch`, puis une phrase), puis `yarn changeset version`.\n   - `version` propage un bump patch aux dépendants internes (`updateInternalDependencies: patch`) : relire le diff des `package.json` et `CHANGELOG.md` générés (ex. un changement dans `database` touche `domain-*`, `outbox`, `workers`, `post-processors`). `yarn check-changelogs` compare à `origin\u002Fmain` sur des commits : il répond « No packages were modified » tant que rien n'est commité.\n4. **🛑 STOP TOTAL** : Arrêt de toute exécution. Informer le Lead Dev que le package est prêt pour la PR.\n5. **Attente de publication** : Attendre le retour de la CI avec la version snapshot ou définitive.\n6. **Consommation** : Reprendre dans les microservices concernés via `yarn up @volontariapp\u002F\u003Cpackage>@\u003Cversion-snapshot>` et adapter le code consommateur.\n\n---\n\n## 2 bis. Ce que fait réellement la CI\n\n`npm-packages\u002F.github\u002Fworkflows\u002Fci.yml` appelle le pipeline réutilisable de `ci-tools`[^pipeline] :\n\n| Étape | Déclencheur | Effet |\n| :--- | :--- | :--- |\n| `check-changelogs` | PR et `main` | Pour chaque package modifié, vérifie que `CHANGELOG.md` contient la version de `package.json` (`yarn check-changelogs`) : sans `yarn changeset version`, la PR est rouge |\n| Orchestration | PR et `main` | Calcule les packages à construire : ceux modifiés **et leurs dépendants internes**, par couches topologiques[^orchestrate] |\n| Build et tests | PR et `main` | Matrice parallèle sur ces packages |\n| Snapshot | PR uniquement | Publie `\u003Cversion>-snap-\u003Csha court>` sous le dist-tag `next`, et liste les versions en commentaire de la PR[^snap] |\n| Release | push sur `main` | Publie la version **déjà écrite** dans `package.json` (ignorée si elle existe déjà sur le registre), puis met à jour le sous-module `npm-packages` du repo `deploy` |\n| Secours | `workflow_dispatch` | `job-emergency-release.yml` (option `dry_run`) |\n| Notification | PR uniquement | Job `notify-ready` du `ci.yml` (`needs: [run-pipeline]`) : un seul message Discord (canal backend) quand la PR est prête, pour une PR Dependabot ou une PR portant le label `notify-discord`. Détail et limites dans `volontariapp-ci-tools` |\n\nConséquences pratiques :\n- Le déclencheur `pull_request` de ce `ci.yml` inclut `labeled` : poser un label (même `notify-discord`) relance tout le pipeline, snapshot compris. C'est pourquoi `notify-ready` ne reçoit pas `ORG_REPO_TOKEN` : un label posé avec un jeton personnel relancerait un run de plus à chaque notification. Conséquence non vérifiée sur une vraie PR Dependabot : le `GITHUB_TOKEN` y est en lecture seule, le job `notify-ready` échouerait au lieu de notifier.\n- Le bump se fait dans la PR : `yarn changeset add` puis `yarn changeset version`, **une seule fois par branche** (deux `version` sur la même branche font sauter une version, 3.1 vers 3.3).\n- La version à mettre dans un consommateur pendant la PR est celle du commentaire de la CI, par exemple `yarn up @volontariapp\u002Fmessaging@2.17.1-snap-a1b2c3d`. Elle change à chaque push sur la PR.\n- Modifier `shared` reconstruit aussi tout ce qui en dépend dans le monorepo : le build de la PR est le premier test d'impact.\n- Les versions déclarées par les consommateurs dérivent : les runners épinglent souvent une version exacte ancienne. Vérifier avec `scripts\u002Fconsumers.py \u003Cpackage>` avant de supposer qu'un consommateur suit la dernière version.\n\n## 2 ter. Avant d'écrire du code avec un package\n\nLes README de plusieurs packages décrivent des API qui n'existent pas (`BaseJobHandler`, `JwtVerifier`, table `event_outbox`). La table des API réelles et des écarts est dans [Catalogue des packages](\u002Fvolontariapp-shared-npm-package-change\u002Freferences\u002Fpackage-catalogue.md). En cas de doute : `smart_search({ query, scope: \"npm-packages\u002Fpackages\u002F\u003Cpackage>\" })`.\n\n## 2 quater. Pièges de développement local dans le monorepo\n\n- **Erreurs ESLint « error typed value » \u002F « Unsafe call of an error type » dans un package consommateur** (ex. `outbox` qui importe un nouvel export de `database`) : le consommateur lit le `dist` du package amont, périmé. Reconstruire dans l'ordre (`yarn --cwd packages\u002F\u003Camont> build`, puis le consommateur) avant de relancer ESLint ; ce n'est pas un vrai défaut de typage.\n- **Colonne nullable : `null` à la lecture, `undefined` à la création.** Une valeur relue depuis Postgres est `null` alors que le type dit `string | undefined`. Normaliser à la frontière (pushers, sérialisation) pour qu'aucun `null` ne parte dans un stream Redis ou un job BullMQ ; seuls les tests d'intégration avec une vraie base le révèlent.\n- **Migrations de test périmées dans `domain-*`** : `packages\u002Fdomain-\u003Cd>\u002Fsrc\u002Ftest\u002Fmigrations\u002F` est une copie de `ms-\u003Cd>\u002Fsrc\u002Fmigrations\u002F` qui dérive (migration manquante, fichier renommé). Symptôme constaté : passer un événement à `FINISHED` échouait avec `invalid input value for enum events_state_enum: \"4\"` parce que `1781400000000-AddFinishedAndCancelledToEventStateEnum` n'était pas copiée. Avant d'écrire un test d'intégration, comparer `ls` des deux dossiers et copier la migration manquante à l'identique (`md5`). Ce n'est pas un bug de production.\n- **Tests d'intégration** (`database`, `outbox`) : Postgres sur `127.0.0.1:5433` avec `testuser`\u002F`testpassword`, base `volontariapp_test`, et Redis `6379` mot de passe `password`. `ci-tools\u002Fdocker-compose.yml` mappe 5433 sur `postgres-post` avec d'autres identifiants : créer le rôle et la base dedans, et ne pas les supprimer s'ils existaient déjà.\n\n## 3. Lien avec `proto-registry`\n\n- Si ta modification de contrat prend sa source dans des fichiers `.proto` (dans `proto-registry`), la chaîne est asynchrone :\n  1. Modification dans `proto-registry`.\n  2. Merge sur `main` dans `proto-registry`.\n  3. La CI de `proto-registry` ouvre\u002Fmet à jour automatiquement une PR dans `npm-packages` pour régénérer `@volontariapp\u002Fcontracts` et `@volontariapp\u002Fcontracts-nest`.\n  4. Cette PR dans `npm-packages` doit être mergée et publiée par la CI.\n  5. **Tu ne dois JAMAIS tenter de toucher aux microservices avant que toute cette boucle ne soit terminée !**\n\n[^pipeline]: Pipeline réutilisable npm-packages (ci-tools)\n[^orchestrate]: ci-orchestrate.py (plan, version snapshot)\n[^snap]: ci-snap-publish.sh (dist-tag next)\n","# Shared NPM Package Change & Règle d'Or du Stop Immédiat\n\nLe répertoire `npm-packages\u002Fpackages\u002F` contient l'ensemble du code partagé entre microservices et leurs processus satellites :\n- **Packages de domaine (`domain-\u003Cdomaine>`)** : partagés entre `ms-\u003Cdomaine>`, `outbox-\u003Cdomaine>`, `worker-\u003Cdomaine>` et `post-processors-runner`.\n- **Packages transverses (`messaging`, `contracts`, `database`, `auth`, `logger`, `errors`, `monitoring`)** : consommés par l'ensemble des 17 dépôts.\n\n---\n\n## 🛑 RÈGLE D'OR ABSOLUE : LE STOP IMMÉDIAT\n\n> [!CAUTION]\n> **DÈS QUE TU AS TERMINÉ DE MODIFIER QUOI QUE CE SOIT DANS `npm-packages` :**\n> 1. Tu vérifies localement la compilation : `yarn build` (et `yarn test`).\n> 2. Tu crées le changeset puis tu appliques le bump : `yarn changeset add` puis `yarn changeset version` (une seule fois par branche).\n> 3. **TU T'ARRÊTES IMMÉDIATEMENT**. Tu ne touches à AUCUN autre fichier ou repository.\n> 4. **INTERDICTION FORMELLE** d'aller modifier, tester ou compiler les microservices consommateurs (`ms-*`, `api-gateway`, runners) en avance.\n> 5. **INTERDICTION FORMELLE** de bricoler des types, d'utiliser du casting `as unknown as Type`, ou de poser du `any` pour faire semblant que le code compile sans le paquet publié.\n> 6. **ACTION EXIGÉE** : Tu passes la main au Lead Dev. Tu lui indiques que les modifications dans `npm-packages` sont prêtes et tu **ATTENDS qu'il pousse sur une PR**.\n> 7. La CI GitHub Actions s'exécute sur la PR et génère une version snapshot `\u003Cversion>-snap-\u003Csha court>`, publiée sous le dist-tag `next` et listée en commentaire de la PR (ex: `@volontariapp\u002Fmessaging@2.17.1-snap-a1b2c3d`) ou définitive sur `main`.\n> 8. **Ce n'est qu'APRÈS la publication effective par la CI** que tu pourras mettre à jour les dépendances dans les microservices consommateurs (`yarn up @volontariapp\u002F\u003Cpkg>@\u003Cversion>`).\n\n---\n\n## 1. Avant de modifier un package partagé (Impact Analysis)\n\nNe jamais modifier un package à l'aveugle :\n1. **Mesurer le rayon d'impact** : Utilise l'outil MCP `find_dependents` pour identifier en $O(1)$ tous les fichiers et services qui importent le package ou symbole modifié :\n   ```json\n   find_dependents({ \"target\": \"@volontariapp\u002Fmessaging\" })\n   find_dependents({ \"target\": \"SignUpCommand\" })\n   ```\n2. **Pour les flux asynchrones** : Si tu modifies un événement ou un job dans `messaging`, utilise l'outil MCP `analyze_impact` pour visualiser les producteurs, consommateurs et sagas impactés :\n   ```json\n   analyze_impact({ \"target\": \"USER_CREATED\" })\n   ```\n\n---\n\n## 2. Déroulement du Workflow Pas-à-Pas\n\n```mermaid\nflowchart TD\n    A[\"1. Édition du code dans npm-packages\u002F\"] --> B[\"2. Validation locale (yarn build & yarn test)\"]\n    B --> C[\"3. Changeset et bump (yarn changeset add puis version)\"]\n    C --> D[\"🛑 4. STOP IMMÉDIAT (Passage de main au Lead Dev)\"]\n    D --> E[\"5. Le Lead Dev push sur PR GitHub\"]\n    E --> F[\"6. La CI publie la version Snapshot \u002F Release\"]\n    F --> G[\"7. Reprise : yarn up dans les microservices consommateurs\"]\n```\n\n1. **Édition locale** : Modifications ciblées dans `npm-packages\u002Fpackages\u002F\u003Cpackage>`.\n2. **Build & Tests** : Vérifier que `yarn build` passe sans aucune erreur.\n3. **Changeset** :\n   - Exécuter `yarn changeset add` et sélectionner les packages modifiés, puis `yarn changeset version` pour écrire la version et le `CHANGELOG.md` que la CI vérifie.\n   - Ne JAMAIS bumper deux fois le même package sur la même branche (ex: pas de 3.1 -> 3.3). Avant `version`, comparer `package.json` à `origin\u002Fmain` : s'il est déjà différent, le bump a eu lieu.\n   - `yarn changeset add` est interactif. Sans TTY, écrire `.changeset\u002F\u003Cnom>.md` (en-tête `'@volontariapp\u002F\u003Cpkg>': minor|patch`, puis une phrase), puis `yarn changeset version`.\n   - `version` propage un bump patch aux dépendants internes (`updateInternalDependencies: patch`) : relire le diff des `package.json` et `CHANGELOG.md` générés (ex. un changement dans `database` touche `domain-*`, `outbox`, `workers`, `post-processors`). `yarn check-changelogs` compare à `origin\u002Fmain` sur des commits : il répond « No packages were modified » tant que rien n'est commité.\n4. **🛑 STOP TOTAL** : Arrêt de toute exécution. Informer le Lead Dev que le package est prêt pour la PR.\n5. **Attente de publication** : Attendre le retour de la CI avec la version snapshot ou définitive.\n6. **Consommation** : Reprendre dans les microservices concernés via `yarn up @volontariapp\u002F\u003Cpackage>@\u003Cversion-snapshot>` et adapter le code consommateur.\n\n---\n\n## 2 bis. Ce que fait réellement la CI\n\n`npm-packages\u002F.github\u002Fworkflows\u002Fci.yml` appelle le pipeline réutilisable de `ci-tools`[^pipeline] :\n\n| Étape | Déclencheur | Effet |\n| :--- | :--- | :--- |\n| `check-changelogs` | PR et `main` | Pour chaque package modifié, vérifie que `CHANGELOG.md` contient la version de `package.json` (`yarn check-changelogs`) : sans `yarn changeset version`, la PR est rouge |\n| Orchestration | PR et `main` | Calcule les packages à construire : ceux modifiés **et leurs dépendants internes**, par couches topologiques[^orchestrate] |\n| Build et tests | PR et `main` | Matrice parallèle sur ces packages |\n| Snapshot | PR uniquement | Publie `\u003Cversion>-snap-\u003Csha court>` sous le dist-tag `next`, et liste les versions en commentaire de la PR[^snap] |\n| Release | push sur `main` | Publie la version **déjà écrite** dans `package.json` (ignorée si elle existe déjà sur le registre), puis met à jour le sous-module `npm-packages` du repo `deploy` |\n| Secours | `workflow_dispatch` | `job-emergency-release.yml` (option `dry_run`) |\n| Notification | PR uniquement | Job `notify-ready` du `ci.yml` (`needs: [run-pipeline]`) : un seul message Discord (canal backend) quand la PR est prête, pour une PR Dependabot ou une PR portant le label `notify-discord`. Détail et limites dans `volontariapp-ci-tools` |\n\nConséquences pratiques :\n- Le déclencheur `pull_request` de ce `ci.yml` inclut `labeled` : poser un label (même `notify-discord`) relance tout le pipeline, snapshot compris. C'est pourquoi `notify-ready` ne reçoit pas `ORG_REPO_TOKEN` : un label posé avec un jeton personnel relancerait un run de plus à chaque notification. Conséquence non vérifiée sur une vraie PR Dependabot : le `GITHUB_TOKEN` y est en lecture seule, le job `notify-ready` échouerait au lieu de notifier.\n- Le bump se fait dans la PR : `yarn changeset add` puis `yarn changeset version`, **une seule fois par branche** (deux `version` sur la même branche font sauter une version, 3.1 vers 3.3).\n- La version à mettre dans un consommateur pendant la PR est celle du commentaire de la CI, par exemple `yarn up @volontariapp\u002Fmessaging@2.17.1-snap-a1b2c3d`. Elle change à chaque push sur la PR.\n- Modifier `shared` reconstruit aussi tout ce qui en dépend dans le monorepo : le build de la PR est le premier test d'impact.\n- Les versions déclarées par les consommateurs dérivent : les runners épinglent souvent une version exacte ancienne. Vérifier avec `scripts\u002Fconsumers.py \u003Cpackage>` avant de supposer qu'un consommateur suit la dernière version.\n\n## 2 ter. Avant d'écrire du code avec un package\n\nLes README de plusieurs packages décrivent des API qui n'existent pas (`BaseJobHandler`, `JwtVerifier`, table `event_outbox`). La table des API réelles et des écarts est dans [Catalogue des packages](\u002Fvolontariapp-shared-npm-package-change\u002Freferences\u002Fpackage-catalogue.md). En cas de doute : `smart_search({ query, scope: \"npm-packages\u002Fpackages\u002F\u003Cpackage>\" })`.\n\n## 2 quater. Pièges de développement local dans le monorepo\n\n- **Erreurs ESLint « error typed value » \u002F « Unsafe call of an error type » dans un package consommateur** (ex. `outbox` qui importe un nouvel export de `database`) : le consommateur lit le `dist` du package amont, périmé. Reconstruire dans l'ordre (`yarn --cwd packages\u002F\u003Camont> build`, puis le consommateur) avant de relancer ESLint ; ce n'est pas un vrai défaut de typage.\n- **Colonne nullable : `null` à la lecture, `undefined` à la création.** Une valeur relue depuis Postgres est `null` alors que le type dit `string | undefined`. Normaliser à la frontière (pushers, sérialisation) pour qu'aucun `null` ne parte dans un stream Redis ou un job BullMQ ; seuls les tests d'intégration avec une vraie base le révèlent.\n- **Migrations de test périmées dans `domain-*`** : `packages\u002Fdomain-\u003Cd>\u002Fsrc\u002Ftest\u002Fmigrations\u002F` est une copie de `ms-\u003Cd>\u002Fsrc\u002Fmigrations\u002F` qui dérive (migration manquante, fichier renommé). Symptôme constaté : passer un événement à `FINISHED` échouait avec `invalid input value for enum events_state_enum: \"4\"` parce que `1781400000000-AddFinishedAndCancelledToEventStateEnum` n'était pas copiée. Avant d'écrire un test d'intégration, comparer `ls` des deux dossiers et copier la migration manquante à l'identique (`md5`). Ce n'est pas un bug de production.\n- **Tests d'intégration** (`database`, `outbox`) : Postgres sur `127.0.0.1:5433` avec `testuser`\u002F`testpassword`, base `volontariapp_test`, et Redis `6379` mot de passe `password`. `ci-tools\u002Fdocker-compose.yml` mappe 5433 sur `postgres-post` avec d'autres identifiants : créer le rôle et la base dedans, et ne pas les supprimer s'ils existaient déjà.\n\n## 3. Lien avec `proto-registry`\n\n- Si ta modification de contrat prend sa source dans des fichiers `.proto` (dans `proto-registry`), la chaîne est asynchrone :\n  1. Modification dans `proto-registry`.\n  2. Merge sur `main` dans `proto-registry`.\n  3. La CI de `proto-registry` ouvre\u002Fmet à jour automatiquement une PR dans `npm-packages` pour régénérer `@volontariapp\u002Fcontracts` et `@volontariapp\u002Fcontracts-nest`.\n  4. Cette PR dans `npm-packages` doit être mergée et publiée par la CI.\n  5. **Tu ne dois JAMAIS tenter de toucher aux microservices avant que toute cette boucle ne soit terminée !**\n\n[^pipeline]: Pipeline réutilisable npm-packages (ci-tools)\n[^orchestrate]: ci-orchestrate.py (plan, version snapshot)\n[^snap]: ci-snap-publish.sh (dist-tag next)\n",{"name":5,"tags":49,"type":51,"paths":52,"title":59,"status":60,"sources":61,"verified":77,"generated":93,"mesh_keys":96,"description":7},[42,40,50],"stop-rule","Agent Skill",[53,54,55,56,57,58],"npm-packages\u002Fpackage.json","npm-packages\u002Fpackages\u002F*\u002Fpackage.json","npm-packages\u002Fpackages\u002F*\u002FCHANGELOG.md","npm-packages\u002Fyarn.lock","npm-packages\u002F.changeset\u002Fconfig.json","npm-packages\u002F.github\u002Fworkflows\u002F**","Shared NPM Package Change","stable",[62,64,68,71,74],{"id":39,"title":63,"resource":57},"Configuration changesets",{"id":65,"title":66,"resource":67},"npm-ci","CI de publication npm-packages","npm-packages\u002F.github\u002Fworkflows",{"id":43,"title":69,"resource":70},"ci-orchestrate.py (plan, version snapshot)","npm-packages\u002Fscripts\u002Fci-orchestrate.py",{"id":31,"title":72,"resource":73},"ci-snap-publish.sh (dist-tag next)","npm-packages\u002Fscripts\u002Fci-snap-publish.sh",{"id":37,"title":75,"resource":76},"Pipeline réutilisable npm-packages (ci-tools)","ci-tools\u002F.github\u002Fworkflows\u002Fnpm-packages-pipeline.yml",[78,82,85,88,91],{"at":79,"by":80,"digest":81},"2026-11-02T11:07:22Z","claude-code\u002Fagent","a449048c4609013e",{"at":83,"by":80,"digest":84},"2026-11-04T21:25:07Z","84e8022a76347fbe",{"at":86,"by":80,"digest":87},"2026-11-08T11:53:22Z","292021b063207bff",{"at":89,"by":80,"digest":90},"2026-11-08T12:07:09Z","94f91136a88eb724",{"at":92,"by":80,"digest":90},"2026-11-08T22:50:47Z",{"at":94,"by":95},"2026-10-06T08:22:12Z","claude-code\u002Fclaude-opus-5-5",[42,97],"@volontariapp\u002F","main","6b8f03b57018fa66da4666071dc17c1577ff45e8",".agents\u002Fskills\u002Fvolontariapp-shared-npm-package-change","https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta","https:\u002F\u002Fgithub.com\u002FVolontariapp","Volontariapp — Application Web\u002FMobile scalabelle construite sur une architecture microservices événementielle (Event-Driven Architecture), implémentant le Trans","2026-11-10 23:40:22",{"source":8,"skillName":5,"commands":106,"prompt":116,"zipAvailable":117},[107,110,113],{"tool":108,"command":109},"npx","npx skills add Volontariapp\u002Fmeta --skill volontariapp-shared-npm-package-change",{"tool":111,"command":112},"bunx","bunx skills add Volontariapp\u002Fmeta --skill volontariapp-shared-npm-package-change",{"tool":114,"command":115},"pnpm","pnpm dlx skills add Volontariapp\u002Fmeta --skill volontariapp-shared-npm-package-change","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-shared-npm-package-change\u002FSKILL.md",true,[119,125,129,133,137],{"path":120,"resourceType":121,"resourceTypeDesc":122,"sizeBytes":123,"sourceHtmlUrl":124},"index.md","REFERENCE","参考文档",1115,"https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-shared-npm-package-change\u002Findex.md",{"path":126,"resourceType":121,"resourceTypeDesc":122,"sizeBytes":127,"sourceHtmlUrl":128},"log.md",13147,"https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-shared-npm-package-change\u002Flog.md",{"path":130,"resourceType":121,"resourceTypeDesc":122,"sizeBytes":131,"sourceHtmlUrl":132},"references\u002Flessons.md",31269,"https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-shared-npm-package-change\u002Freferences\u002Flessons.md",{"path":134,"resourceType":121,"resourceTypeDesc":122,"sizeBytes":135,"sourceHtmlUrl":136},"references\u002Fpackage-catalogue.md",7572,"https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-shared-npm-package-change\u002Freferences\u002Fpackage-catalogue.md",{"path":138,"resourceType":139,"resourceTypeDesc":140,"sizeBytes":141,"sourceHtmlUrl":142},"scripts\u002Fconsumers.py","SCRIPT","脚本",2207,"https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-shared-npm-package-change\u002Fscripts\u002Fconsumers.py",[144,167,194,217,240,260],{"skillNo":145,"name":146,"nameZh":6,"description":147,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":148,"categories":149,"keywords":150,"publishedAt":44},"01M6CSW3Y5ZHVBF5BX7S5BAVS0","volontariapp-user-account-deletion","Suppression de compte en deux temps (PENDING_DELETION): requestDeletionWithUserDeleted, finalizeDeletion, fan-out de user.deleted vers les domaines et gather ws. A utiliser pour tout changement de domain-user touchant la suppression, le statut ou le cycle de vie d'un user.","https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-user-account-deletion\u002FSKILL.md",[],[151,152,153,154,155,156,157,158,159,32,160,161,27,162,163,164,165,42,166],"volontariapp user account deletion","user","account deletion","deletion","cycle","gather","sonnet","pending","de","claude-code","reference","user-account-deletion","src","en","domain","packages",{"skillNo":168,"name":169,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":171,"categories":172,"keywords":178,"publishedAt":44},"01M6CSVC1ZW30DDFZ8VMEYAAK6","volontariapp-proto-contract-evolution","Modifier un contrat Protobuf de proto-registry (champ, message, enum, RPC) sans casser la compatibilité wire, puis suivre la cascade proto-registry, PR automatique dans npm-packages, publication, consommateurs. À utiliser avant toute édition d'un .proto.","https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-proto-contract-evolution\u002FSKILL.md",[173],{"categoryNo":174,"categoryName":175,"taxonomyType":176,"taxonomyTypeDesc":177},"01JBSEEDCAT000000000000037","律师与法务","PROFESSION","适用职业",[179,180,181,182,32,33,183,166,184,35,185,186,187,27,188,189,190,191,192,193],"evolution","volontariapp proto contract evolution","grpc","lint","analyze","rpc","pr","protobuf","message","registry","sans","sync","yaml","playbook","github",{"skillNo":195,"name":196,"nameZh":6,"description":197,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":198,"categories":199,"keywords":201,"publishedAt":44},"01M6CSV99ET2Z9W4W4DAK4CMQP","volontariapp-meta-scripts","Utiliser et faire evoluer la CLI Node de meta (setup, doctor, migrate, certs, repos, bump) et le manifeste repos.json, source unique des repos et unites du workspace.","https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-meta-scripts\u002FSKILL.md",[200],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[202,203,204,32,205,160,206,207,208,209,210,211,212,213,214,215,216],"Meta","volontariapp meta scripts","repos","migrate","setup","meta-scripts","json","node","workspace","shell","bump","cli","doctor","draft","install",{"skillNo":218,"name":219,"nameZh":6,"description":220,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":221,"categories":222,"keywords":226,"publishedAt":44},"01M6CSTPHNTGE0WF5CPE8W7ZYQ","volontariapp-implement-async-event-flow","Guide pas-à-pas pour concevoir et implémenter un flux asynchrone complet (messaging -> outbox -> post-processors -> ws-service -> client).","https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-implement-async-event-flow\u002FSKILL.md",[223],{"categoryNo":224,"categoryName":225,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",[227,228,229,230,231,41,163,232,233,188,234,235,42,29,236,166,237,238,32,239],"async","implement","volontariapp implement async event flow","flow","event","mapping","flux","streams","flows","outbox","processor","architecture","runner",{"skillNo":241,"name":242,"nameZh":6,"description":243,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":244,"categories":245,"keywords":249,"publishedAt":44},"01M6CSRQHS0T9955M8CTA5BYJQ","research","Investigate a question against high-trust primary sources and capture the findings as a Markdown file in the repo. Use when the user wants a topic researched, docs or API facts gathered, or reading legwork delegated to a background agent.","https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fplugins\u002Fmatt-pocock\u002Fskills\u002Fresearch\u002FSKILL.md",[246],{"categoryNo":247,"categoryName":248,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000021","资料检索与研究",[242,250,152,251,252,253,254,255,256,257,258,259],"api","file","repo","markdown","docs","capture","use","question","trust","investigate",{"skillNo":261,"name":262,"nameZh":6,"description":263,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":264,"categories":265,"keywords":269,"publishedAt":44},"01M6CSRMZ82M1YK96Z4SW1STTD","prototype","Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like.","https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fplugins\u002Fmatt-pocock\u002Fskills\u002Fprototype\u002FSKILL.md",[266],{"categoryNo":267,"categoryName":268,"taxonomyType":176,"taxonomyTypeDesc":177},"01JBSEEDCAT000000000000032","设计师",[262,270,152,271,256,272,257,273,274,275,276,277],"check","ui","look","design","explore","model","build","state"]