[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CSSV6GV9M508HT7PYZMYDA":3,"skill-same:01M6CSSV6GV9M508HT7PYZMYDA":132},{"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":97,"commitSha":98,"skillDirectory":99,"forksCount":14,"repositoryHtmlUrl":100,"repositoryHomepageUrl":6,"ownerHtmlUrl":101,"ownerBlogUrl":6,"ownerDescription":102,"updatedAt":103,"install":104,"resources":117},"01M6CSSV6GV9M508HT7PYZMYDA","volontariapp-async-remediation",null,"Playbook opérationnel pas-à-pas pour diagnostiquer, débloquer et réconcilier les pannes asynchrones (Poison pills DLQ, Redis Streams XCLAIM\u002FXACK, réconciliation SQL outbox).","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-async-remediation\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"async","remediation","volontariapp async remediation","helper","local","streams","retry","types","npm-packages","file","database","workers","files","runners","core","xack","xclaim","runner","redis-streams","dlq","2026-11-10 10:12:30",false,"---\nname: volontariapp-async-remediation\ndescription: \"Playbook opérationnel pas-à-pas pour diagnostiquer, débloquer et réconcilier les pannes asynchrones (Poison pills DLQ, Redis Streams XCLAIM\u002FXACK, réconciliation SQL outbox).\"\ntype: Playbook\ntitle: \"Remédiation et Dépilement des Files Asynchrones (DLQ & Streams)\"\ntags: [async, remediation, dlq, redis-streams, xclaim, xack, outbox, playbook]\nstatus: stable\npaths:\n  - \"post-processors-runner\u002F**\"\n  - \"workers-runners\u002F**\"\n  - \"npm-packages\u002Fpackages\u002Fpost-processors\u002F**\"\nmesh_keys:\n  - dlq-remediation\n  - xclaim-recovery\n  - stream-remediation\ngenerated:\n  by: claude-code\u002Fagent\n  at: \"2026-10-12T11:58:00Z\"\nverified:\n  - by: claude-code\u002Fagent\n    at: \"2026-11-04T21:34:45Z\"\n    digest: 33b9ef4b5b3df65a\n  - by: claude-code\u002Fagent\n    at: \"2026-11-04T21:36:01Z\"\n    digest: 036777c37dd4f448\n  - by: claude-code\u002Fagent\n    at: \"2026-11-07T23:14:09Z\"\n    digest: 2360205de2f7abcd\n  - by: claude-code\u002Fagent\n    at: \"2026-11-07T23:14:26Z\"\n    digest: 2360205de2f7abcd\n  - by: claude-code\u002Fagent\n    at: \"2026-11-08T12:02:22Z\"\n    digest: 9c93894442a0fd6f\n  - by: claude-code\u002Fagent\n    at: \"2026-11-08T12:07:09Z\"\n    digest: 2a04ea25b2d069e3\nsources:\n  - id: retry\n    kind: local_file\n    resource: npm-packages\u002Fpackages\u002Fpost-processors\u002Fsrc\u002Fcore\u002Fhelpers\u002Fretry.helper.ts\n    title: \"RetryHelper (DLQ \u003Cstream>-dlq)\"\n  - id: outbox-status\n    kind: local_file\n    resource: npm-packages\u002Fpackages\u002Fdatabase\u002Fsrc\u002Foutbox\u002Ftypes\u002Foutbox.status.ts\n    title: OutboxStatus\n  - id: panne\n    kind: local_file\n    resource: docs\u002Fstockage-fichiers\u002F11-scenarios-de-panne.md\n    title: \"Scénarios de panne, problèmes P2 et P4\"\n---\n\n# Remédiation et Dépilement des Files Asynchrones (DLQ & Streams)\n\n## Quand utiliser ce playbook\n\nUtiliser ce playbook pour intervenir en production ou en environnement de test en cas d'incident sur un flux asynchrone :\n- Messages arrivés en fin de tentatives et routés vers la Dead Letter Queue (`\u003Cstream>-dlq`)[^retry].\n- Blocage d'un groupe de consommateurs Redis Streams (consommateur crashé, PEL saturée).\n- Erreur récurrente sur un Job BullMQ sans reprise automatique.\n- Désynchronisation ou blocage persistant de statut dans `jobs_outbox`, `event_queue` ou `job_audit`[^outbox-status].\n\n*(Pour une phase d'audit passif préalable sans action corrective, se référer à la skill d'investigation `volontariapp-trace-async-flow`).*\n\n---\n\n## Règles d'or d'intervention\n\n1. **Aucune suppression aveugle** : Ne jamais exécuter un `XDEL` ou purger une DLQ sans avoir copié et sauvegardé le payload JSON incriminé.\n2. **Idempotence des consommateurs** : Tout rejeu de message (`replay`) suppose que le consommateur cible supporte d'être appelé deux fois pour la même action (gestion du « déjà traité »).\n3. **Consistance transactionnelle bilatérale** : Débloquer un message dans Redis nécessite systématiquement de vérifier et réconcilier l'état de la ligne correspondante dans la base PostgreSQL du microservice émetteur (`event_queue` ou `jobs_outbox`)[^panne].\n\n---\n\n## Procédure pas-à-pas\n\n### Étape 1 : Inspection de la Poison Pill dans la DLQ\n\nLorsqu'un post-processor échoue après `maxRetries` (par défaut 5 tentatives), `RetryHelper` bascule le message dans `\u003Cstream>-dlq`[^retry].\n\nSeules les erreurs métier suivent ce chemin. Une erreur d'infrastructure (connexion base ou Redis refusée ou perdue, timeout, détectée par `isInfrastructureError` de `@volontariapp\u002Ferrors`) ne compte aucune tentative et n'envoie rien en DLQ : le message reste dans la PEL et le consumer le relit `claimIntervalMs` plus tard (un message absent de la DLQ pendant une panne de base est donc normal). Chaque occurrence est loguée en `warn` (`Infrastructure error, message kept pending`) avec le stream et l'id du message. Le circuit breaker, lui, compte toujours l'échec.\n\n1. Se connecter à l'instance Redis :\n   ```bash\n   redis-cli\n   ```\n2. Inspecter les derniers messages en DLQ :\n   ```text\n   XRANGE \u003Cstream>-dlq - + COUNT 10\n   ```\n3. Chaque entrée contient :\n   - `messageId` : ID d'origine du message dans le flux initial.\n   - `error` : Message et stacktrace de l'exception ayant provoqué l'échec.\n   - `payload` : Contenu JSON complet de l'événement d'origine.\n   - `timestamp` : Horodatage du basculement en DLQ.\n4. Sauvegarder localement le `payload` et analyser la racine de l'échec (ex. entité introuvable, schéma désynchronisé, contrainte de clé étrangère violée).\n\n---\n\n### Étape 2 : Déblocage des messages orphelins (Pending Entries List)\n\nSi un worker ou post-processor a crashé pendant le traitement, le message reste bloqué dans la Pending Entries List (PEL) sans être ni acquitté ni retenté.\n\nLe claim (`claimPendingMessages`) ignore les messages du même consumer : un message resté en PEL chez un consumer vivant n'est relu que lorsque `readPending` repasse à `true` (démarrage, claim, file de retry, ou relecture planifiée après une erreur d'infrastructure). Piège connu : le verrou d'idempotence d'un message (`SET NX`, TTL `idempotencyTtlSeconds`, 24 h) non libéré parce que Redis était indisponible fait traiter la relecture comme « déjà traité » : le message est alors acquitté sans effet. Dans ce cas, supprimer la clé de verrou (`RedisStreamHelper.getIdempotencyKey`) avant de redémarrer le pod, car le démarrage relit la PEL.\n\n1. Vérifier les messages en souffrance pour le groupe consommateur :\n   ```text\n   XPENDING \u003Cstream> \u003Cnom-du-groupe>\n   ```\n2. Lister les identifiants et les consommateurs assignés :\n   ```text\n   XPENDING \u003Cstream> \u003Cnom-du-groupe> - + 10\n   ```\n3. Si un consommateur est inactif depuis plus de 5 minutes (300 000 ms), réclamer le message au profit d'un consommateur sain via `XCLAIM` :\n   ```text\n   XCLAIM \u003Cstream> \u003Cnom-du-groupe> \u003Cnouveau-consommateur> 300000 \u003CmessageId>\n   ```\n4. Si le message a été traité avec succès de manière externe, l'acquitter manuellement :\n   ```text\n   XACK \u003Cstream> \u003Cnom-du-groupe> \u003CmessageId>\n   ```\n\n---\n\n### Étape 3 : Correction de la cause racine\n\nAvant toute réinjection :\n1. **Si bug de logique applicative** : Livrer le correctif dans le microservice ou le post-processor (`post-processors-runner`), redémarrer le pod.\n2. **Si anomalie de données en base** : Corriger la donnée orpheline ou invalide directement dans la base PostgreSQL du service concerné.\n\n---\n\n### Étape 4 : Réinjection sécurisée (Replay) depuis la DLQ\n\nUne fois le correctif en place :\n1. Rejouer l'événement dans le flux nominal :\n   ```text\n   XADD \u003Cstream> * payload '\u003Cjson-payload-corrigé>'\n   ```\n2. Confirmer la prise en charge et le traitement réussi par le post-processor via les logs applicatifs.\n3. Purger le message résolu de la DLQ pour maintenir la file propre :\n   ```text\n   XDEL \u003Cstream>-dlq \u003Cid-du-message-dlq>\n   ```\n4. Nettoyer les clés de métadonnées de retry résiduelles créées par `RetryHelper`[^retry] :\n   ```text\n   DEL retry:post-processor:\u003Cgroupe>:\u003CmessageId>\n   DEL retry:post-processor:\u003Cgroupe>:\u003CmessageId>:attempt\n   DEL retry:post-processor:\u003Cgroupe>:\u003CmessageId>:lastError\n   ZREM retry-queue:post-processor:\u003Cgroupe> \u003CmessageId>\n   ```\n\n---\n\n### Étape 5 : Réconciliation transactionnelle SQL\n\nPour garantir la cohérence des compteurs et des sagas métier :\n1. Identifier la ligne dans la base du microservice émetteur (`event_queue` ou `jobs_outbox`)[^outbox-status] :\n   ```sql\n   SELECT id, event_name, status, retry_count, last_error\n   FROM event_queue\n   WHERE id = '\u003Cid-evenement>';\n   ```\n2. Si le message a été réinjecté et traité, synchroniser le statut :\n   ```sql\n   UPDATE event_queue\n   SET status = 'COMPLETED', updated_at = NOW()\n   WHERE id = '\u003Cid-evenement>' AND status = 'FAILED';\n   ```\n3. Vérifier la table `job_audit` pour confirmer la clôture propre du cycle d'exécution.\n\n---\n\n### Étape 6 : Enregistrement du piège (Boucle de progrès)\n\nSi la panne a révélé une vulnérabilité d'architecture ou un comportement inattendu, consigner immédiatement la leçon apprise :\n```bash\npython3 .agents\u002Fskills\u002Fvolontariapp-skill-evolution\u002Fscripts\u002Fevolve.py learn \\\n  --skill volontariapp-async-remediation \\\n  --kind pitfall \\\n  --rule \"Description de la cause racine et de la règle pour éviter la récidive.\"\n```\n\n---\n\n## Checklist de remédiation\n\n- [ ] Le payload du message en échec a été exporté et analysé depuis `\u003Cstream>-dlq`[^retry].\n- [ ] La PEL Redis a été auditée (`XPENDING`) et les messages orphelins réclamés (`XCLAIM`) ou acquittés (`XACK`).\n- [ ] La cause racine (applicative ou modèle de données) a été corrigée et vérifiée.\n- [ ] Le message a été réinjecté (`XADD`) et traité avec succès par les consommateurs.\n- [ ] Le message traité a été supprimé de la DLQ (`XDEL`) et les clés de retry nettoyées.\n- [ ] Les statuts de l'outbox relationnelle (`event_queue` \u002F `jobs_outbox`) ont été réconciliés (`COMPLETED`)[^outbox-status].\n- [ ] La leçon a été consignée via `evolve.py learn` si un piège structurel a été mis en évidence.\n\n---\n\n## Références\n\n[^retry]: npm-packages\u002Fpackages\u002Fpost-processors\u002Fsrc\u002Fcore\u002Fhelpers\u002Fretry.helper.ts\n[^outbox-status]: npm-packages\u002Fpackages\u002Fdatabase\u002Fsrc\u002Foutbox\u002Ftypes\u002Foutbox.status.ts\n[^panne]: docs\u002Fstockage-fichiers\u002F11-scenarios-de-panne.md\n","# Remédiation et Dépilement des Files Asynchrones (DLQ & Streams)\n\n## Quand utiliser ce playbook\n\nUtiliser ce playbook pour intervenir en production ou en environnement de test en cas d'incident sur un flux asynchrone :\n- Messages arrivés en fin de tentatives et routés vers la Dead Letter Queue (`\u003Cstream>-dlq`)[^retry].\n- Blocage d'un groupe de consommateurs Redis Streams (consommateur crashé, PEL saturée).\n- Erreur récurrente sur un Job BullMQ sans reprise automatique.\n- Désynchronisation ou blocage persistant de statut dans `jobs_outbox`, `event_queue` ou `job_audit`[^outbox-status].\n\n*(Pour une phase d'audit passif préalable sans action corrective, se référer à la skill d'investigation `volontariapp-trace-async-flow`).*\n\n---\n\n## Règles d'or d'intervention\n\n1. **Aucune suppression aveugle** : Ne jamais exécuter un `XDEL` ou purger une DLQ sans avoir copié et sauvegardé le payload JSON incriminé.\n2. **Idempotence des consommateurs** : Tout rejeu de message (`replay`) suppose que le consommateur cible supporte d'être appelé deux fois pour la même action (gestion du « déjà traité »).\n3. **Consistance transactionnelle bilatérale** : Débloquer un message dans Redis nécessite systématiquement de vérifier et réconcilier l'état de la ligne correspondante dans la base PostgreSQL du microservice émetteur (`event_queue` ou `jobs_outbox`)[^panne].\n\n---\n\n## Procédure pas-à-pas\n\n### Étape 1 : Inspection de la Poison Pill dans la DLQ\n\nLorsqu'un post-processor échoue après `maxRetries` (par défaut 5 tentatives), `RetryHelper` bascule le message dans `\u003Cstream>-dlq`[^retry].\n\nSeules les erreurs métier suivent ce chemin. Une erreur d'infrastructure (connexion base ou Redis refusée ou perdue, timeout, détectée par `isInfrastructureError` de `@volontariapp\u002Ferrors`) ne compte aucune tentative et n'envoie rien en DLQ : le message reste dans la PEL et le consumer le relit `claimIntervalMs` plus tard (un message absent de la DLQ pendant une panne de base est donc normal). Chaque occurrence est loguée en `warn` (`Infrastructure error, message kept pending`) avec le stream et l'id du message. Le circuit breaker, lui, compte toujours l'échec.\n\n1. Se connecter à l'instance Redis :\n   ```bash\n   redis-cli\n   ```\n2. Inspecter les derniers messages en DLQ :\n   ```text\n   XRANGE \u003Cstream>-dlq - + COUNT 10\n   ```\n3. Chaque entrée contient :\n   - `messageId` : ID d'origine du message dans le flux initial.\n   - `error` : Message et stacktrace de l'exception ayant provoqué l'échec.\n   - `payload` : Contenu JSON complet de l'événement d'origine.\n   - `timestamp` : Horodatage du basculement en DLQ.\n4. Sauvegarder localement le `payload` et analyser la racine de l'échec (ex. entité introuvable, schéma désynchronisé, contrainte de clé étrangère violée).\n\n---\n\n### Étape 2 : Déblocage des messages orphelins (Pending Entries List)\n\nSi un worker ou post-processor a crashé pendant le traitement, le message reste bloqué dans la Pending Entries List (PEL) sans être ni acquitté ni retenté.\n\nLe claim (`claimPendingMessages`) ignore les messages du même consumer : un message resté en PEL chez un consumer vivant n'est relu que lorsque `readPending` repasse à `true` (démarrage, claim, file de retry, ou relecture planifiée après une erreur d'infrastructure). Piège connu : le verrou d'idempotence d'un message (`SET NX`, TTL `idempotencyTtlSeconds`, 24 h) non libéré parce que Redis était indisponible fait traiter la relecture comme « déjà traité » : le message est alors acquitté sans effet. Dans ce cas, supprimer la clé de verrou (`RedisStreamHelper.getIdempotencyKey`) avant de redémarrer le pod, car le démarrage relit la PEL.\n\n1. Vérifier les messages en souffrance pour le groupe consommateur :\n   ```text\n   XPENDING \u003Cstream> \u003Cnom-du-groupe>\n   ```\n2. Lister les identifiants et les consommateurs assignés :\n   ```text\n   XPENDING \u003Cstream> \u003Cnom-du-groupe> - + 10\n   ```\n3. Si un consommateur est inactif depuis plus de 5 minutes (300 000 ms), réclamer le message au profit d'un consommateur sain via `XCLAIM` :\n   ```text\n   XCLAIM \u003Cstream> \u003Cnom-du-groupe> \u003Cnouveau-consommateur> 300000 \u003CmessageId>\n   ```\n4. Si le message a été traité avec succès de manière externe, l'acquitter manuellement :\n   ```text\n   XACK \u003Cstream> \u003Cnom-du-groupe> \u003CmessageId>\n   ```\n\n---\n\n### Étape 3 : Correction de la cause racine\n\nAvant toute réinjection :\n1. **Si bug de logique applicative** : Livrer le correctif dans le microservice ou le post-processor (`post-processors-runner`), redémarrer le pod.\n2. **Si anomalie de données en base** : Corriger la donnée orpheline ou invalide directement dans la base PostgreSQL du service concerné.\n\n---\n\n### Étape 4 : Réinjection sécurisée (Replay) depuis la DLQ\n\nUne fois le correctif en place :\n1. Rejouer l'événement dans le flux nominal :\n   ```text\n   XADD \u003Cstream> * payload '\u003Cjson-payload-corrigé>'\n   ```\n2. Confirmer la prise en charge et le traitement réussi par le post-processor via les logs applicatifs.\n3. Purger le message résolu de la DLQ pour maintenir la file propre :\n   ```text\n   XDEL \u003Cstream>-dlq \u003Cid-du-message-dlq>\n   ```\n4. Nettoyer les clés de métadonnées de retry résiduelles créées par `RetryHelper`[^retry] :\n   ```text\n   DEL retry:post-processor:\u003Cgroupe>:\u003CmessageId>\n   DEL retry:post-processor:\u003Cgroupe>:\u003CmessageId>:attempt\n   DEL retry:post-processor:\u003Cgroupe>:\u003CmessageId>:lastError\n   ZREM retry-queue:post-processor:\u003Cgroupe> \u003CmessageId>\n   ```\n\n---\n\n### Étape 5 : Réconciliation transactionnelle SQL\n\nPour garantir la cohérence des compteurs et des sagas métier :\n1. Identifier la ligne dans la base du microservice émetteur (`event_queue` ou `jobs_outbox`)[^outbox-status] :\n   ```sql\n   SELECT id, event_name, status, retry_count, last_error\n   FROM event_queue\n   WHERE id = '\u003Cid-evenement>';\n   ```\n2. Si le message a été réinjecté et traité, synchroniser le statut :\n   ```sql\n   UPDATE event_queue\n   SET status = 'COMPLETED', updated_at = NOW()\n   WHERE id = '\u003Cid-evenement>' AND status = 'FAILED';\n   ```\n3. Vérifier la table `job_audit` pour confirmer la clôture propre du cycle d'exécution.\n\n---\n\n### Étape 6 : Enregistrement du piège (Boucle de progrès)\n\nSi la panne a révélé une vulnérabilité d'architecture ou un comportement inattendu, consigner immédiatement la leçon apprise :\n```bash\npython3 .agents\u002Fskills\u002Fvolontariapp-skill-evolution\u002Fscripts\u002Fevolve.py learn \\\n  --skill volontariapp-async-remediation \\\n  --kind pitfall \\\n  --rule \"Description de la cause racine et de la règle pour éviter la récidive.\"\n```\n\n---\n\n## Checklist de remédiation\n\n- [ ] Le payload du message en échec a été exporté et analysé depuis `\u003Cstream>-dlq`[^retry].\n- [ ] La PEL Redis a été auditée (`XPENDING`) et les messages orphelins réclamés (`XCLAIM`) ou acquittés (`XACK`).\n- [ ] La cause racine (applicative ou modèle de données) a été corrigée et vérifiée.\n- [ ] Le message a été réinjecté (`XADD`) et traité avec succès par les consommateurs.\n- [ ] Le message traité a été supprimé de la DLQ (`XDEL`) et les clés de retry nettoyées.\n- [ ] Les statuts de l'outbox relationnelle (`event_queue` \u002F `jobs_outbox`) ont été réconciliés (`COMPLETED`)[^outbox-status].\n- [ ] La leçon a été consignée via `evolve.py learn` si un piège structurel a été mis en évidence.\n\n---\n\n## Références\n\n[^retry]: npm-packages\u002Fpackages\u002Fpost-processors\u002Fsrc\u002Fcore\u002Fhelpers\u002Fretry.helper.ts\n[^outbox-status]: npm-packages\u002Fpackages\u002Fdatabase\u002Fsrc\u002Foutbox\u002Ftypes\u002Foutbox.status.ts\n[^panne]: docs\u002Fstockage-fichiers\u002F11-scenarios-de-panne.md\n",{"name":5,"tags":49,"type":52,"paths":53,"title":57,"status":58,"sources":59,"verified":72,"generated":91,"mesh_keys":93,"description":7},[24,25,43,42,40,39,50,51],"outbox","playbook","Playbook",[54,55,56],"post-processors-runner\u002F**","workers-runners\u002F**","npm-packages\u002Fpackages\u002Fpost-processors\u002F**","Remédiation et Dépilement des Files Asynchrones (DLQ & Streams)","stable",[60,64,68],{"id":30,"kind":61,"title":62,"resource":63},"local_file","RetryHelper (DLQ \u003Cstream>-dlq)","npm-packages\u002Fpackages\u002Fpost-processors\u002Fsrc\u002Fcore\u002Fhelpers\u002Fretry.helper.ts",{"id":65,"kind":61,"title":66,"resource":67},"outbox-status","OutboxStatus","npm-packages\u002Fpackages\u002Fdatabase\u002Fsrc\u002Foutbox\u002Ftypes\u002Foutbox.status.ts",{"id":69,"kind":61,"title":70,"resource":71},"panne","Scénarios de panne, problèmes P2 et P4","docs\u002Fstockage-fichiers\u002F11-scenarios-de-panne.md",[73,77,80,83,85,88],{"at":74,"by":75,"digest":76},"2026-11-04T21:34:45Z","claude-code\u002Fagent","33b9ef4b5b3df65a",{"at":78,"by":75,"digest":79},"2026-11-04T21:36:01Z","036777c37dd4f448",{"at":81,"by":75,"digest":82},"2026-11-07T23:14:09Z","2360205de2f7abcd",{"at":84,"by":75,"digest":82},"2026-11-07T23:14:26Z",{"at":86,"by":75,"digest":87},"2026-11-08T12:02:22Z","9c93894442a0fd6f",{"at":89,"by":75,"digest":90},"2026-11-08T12:07:09Z","2a04ea25b2d069e3",{"at":92,"by":75},"2026-10-12T11:58:00Z",[94,95,96],"dlq-remediation","xclaim-recovery","stream-remediation","main","6b8f03b57018fa66da4666071dc17c1577ff45e8",".agents\u002Fskills\u002Fvolontariapp-async-remediation","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":105,"prompt":115,"zipAvailable":116},[106,109,112],{"tool":107,"command":108},"npx","npx skills add Volontariapp\u002Fmeta --skill volontariapp-async-remediation",{"tool":110,"command":111},"bunx","bunx skills add Volontariapp\u002Fmeta --skill volontariapp-async-remediation",{"tool":113,"command":114},"pnpm","pnpm dlx skills add Volontariapp\u002Fmeta --skill volontariapp-async-remediation","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-async-remediation\u002FSKILL.md",true,[118,124,128],{"path":119,"resourceType":120,"resourceTypeDesc":121,"sizeBytes":122,"sourceHtmlUrl":123},"index.md","REFERENCE","参考文档",602,"https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-async-remediation\u002Findex.md",{"path":125,"resourceType":120,"resourceTypeDesc":121,"sizeBytes":126,"sourceHtmlUrl":127},"log.md",9305,"https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-async-remediation\u002Flog.md",{"path":129,"resourceType":120,"resourceTypeDesc":121,"sizeBytes":130,"sourceHtmlUrl":131},"references\u002Flessons.md",1705,"https:\u002F\u002Fgithub.com\u002FVolontariapp\u002Fmeta\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fvolontariapp-async-remediation\u002Freferences\u002Flessons.md",[133,158,186,211,232,251],{"skillNo":134,"name":135,"nameZh":6,"description":136,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":137,"categories":138,"keywords":139,"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",[],[140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,32,157],"volontariapp user account deletion","user","account deletion","deletion","cycle","gather","sonnet","pending","de","code","claude-code","reference","npm","user-account-deletion","src","en","domain","packages",{"skillNo":159,"name":160,"nameZh":6,"description":161,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":162,"categories":163,"keywords":169,"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",[164],{"categoryNo":165,"categoryName":166,"taxonomyType":167,"taxonomyTypeDesc":168},"01JBSEEDCAT000000000000037","律师与法务","PROFESSION","适用职业",[170,171,172,173,149,174,175,157,176,177,178,179,180,152,181,182,183,184,51,185],"evolution","volontariapp proto contract evolution","grpc","lint","workflows","analyze","rpc","ci","pr","protobuf","message","registry","sans","sync","yaml","github",{"skillNo":187,"name":188,"nameZh":6,"description":189,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":190,"categories":191,"keywords":195,"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",[192],{"categoryNo":193,"categoryName":194,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[196,197,198,149,199,150,200,201,202,203,204,205,206,207,208,209,210],"Meta","volontariapp meta scripts","repos","migrate","setup","meta-scripts","json","node","workspace","shell","bump","cli","doctor","draft","install",{"skillNo":212,"name":213,"nameZh":6,"description":214,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":215,"categories":216,"keywords":220,"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",[217],{"categoryNo":218,"categoryName":219,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",[24,221,222,223,224,225,154,226,227,181,29,228,32,229,50,157,230,231,149,41],"implement","volontariapp implement async event flow","flow","event","messaging","mapping","flux","flows","shared","processor","architecture",{"skillNo":233,"name":234,"nameZh":6,"description":235,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":236,"categories":237,"keywords":241,"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",[238],{"categoryNo":239,"categoryName":240,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000021","资料检索与研究",[234,242,141,33,243,244,245,246,247,248,249,250],"api","repo","markdown","docs","capture","use","question","trust","investigate",{"skillNo":252,"name":253,"nameZh":6,"description":254,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":255,"categories":256,"keywords":260,"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",[257],{"categoryNo":258,"categoryName":259,"taxonomyType":167,"taxonomyTypeDesc":168},"01JBSEEDCAT000000000000032","设计师",[253,261,141,262,247,263,248,264,265,266,267,268],"check","ui","look","design","explore","model","build","state"]