PD-293 — Décomposition multi-agents (step 6a)¶
Le code-contracts.yaml existe → workflow multi-agents activé. Voici la décomposition en tâches agents, cohérente avec les 4 waves du plan.
Wave 1 — Modules fondamentaux (parallélisables)¶
Agent 1 : agent-fsm → C1 state-machine¶
Fichier : scripts/lib/lord-state-machine.sh
Mission : Implémenter la machine d'états Ringbearer §5.2 avec matrice de transitions en declare -A.
Interfaces contractuelles : - lord_transition(story_id, from_state, to_state) → OK | REJECTED - lord_is_terminal(state) → true | false
- lord_allowed_transitions(from_state) → liste des to_state autorisés
Matrice des 8 états × transitions autorisées :
| From | To autorisés |
|---|---|
| STARTING | RUNNING, START_FAILED |
| RUNNING | ESCALADED, PAUSED, DONE, ABORTED, CRASHED |
| ESCALADED | RUNNING, ABORTED, CRASHED |
| PAUSED | RUNNING, ABORTED, CRASHED |
| DONE | ∅ (terminal) |
| ABORTED | ∅ (terminal) |
| CRASHED | ∅ (terminal) |
| START_FAILED | ∅ (terminal) |
Invariants couverts : INV-293-09, INV-293-10, INV-293-06
Tests unitaires ciblés : TC-INV-01 (matrice 8×8 exhaustive), TC-INV-02 (terminaux immuables)
Approche alternative considérée : case/esac imbriqués — écarté car verbose et risque d'oubli d'une paire. Le declare -A offre un lookup O(1) et une matrice vérifiable par diff avec §5.2.
Agent 2 : agent-validator → C2 validator¶
Fichier : scripts/lib/lord-validator.sh
Mission : Implémenter les 8 validateurs de champs §5.1 + le logger de rejet §6.1.
Interfaces contractuelles : - lord_validate_story_id(value) → regex ^PD-[0-9]{1,4}$ - lord_validate_project_code(value) → enum 8 valeurs - lord_validate_message_type(value) → enum 8 valeurs - lord_validate_peer_id(value) → `[\p{C}
]{1,128}$(viagrep -P) -lord_validate_timestamp(value)→ regex stricte UTC Z :\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(.\d+)?Z$-lord_validate_escalade_text(value)→[^\p{C}]{1,2000}$(viagrep -P) -lord_validate_summary_text(value)→[\p{C}]{1,512}$-lord_validate_idempotency_key(value)→^[A-Za-z0-9:_-]{16,80}$-lord_log_rejection(timestamp, peer_id, message_type, reason, story_id, event)` → JSONL
Décisions clés : - 6/8 validateurs en regex Bash natif [[ =~ ]] (zéro dépendance) - 2 validateurs (peer_id, escalade_text) nécessitent grep -P (GNU grep) pour \p{C} (H-TECH-04) - Convention rejets Sovereign : peer_id="sovereign", message_type=<COMMAND_NAME> - Timestamp : strictement Z, tout offset non-zero rejeté (H-TECH-08)
Invariant couvert : INV-293-05
Tests unitaires ciblés : TC-NOM-10, TC-ERR-03, TC-NEG-01..TC-NEG-10
Wave 2 — Modules infrastructure (parallélisables, dépendent de C2)¶
Agent 3 : agent-broker → C3 broker-adapter¶
Fichier : scripts/lib/lord-broker.sh
Mission : Couche d'abstraction claude-peers-mcp — listing, envoi, réception, health check, reconnexion.
Interfaces contractuelles : - lord_broker_list_peers() → JSON array | ERROR - lord_broker_send_message(peer_id, message_type, payload) → OK | ERROR - lord_broker_get_messages(peer_id) → JSON array | ERROR - lord_broker_status() → UP | DEGRADED | DOWN - lord_broker_reconnect() → OK | STILL_DEGRADED
Mécanisme de reconnexion : backoff exponentiel borné 1s → 2s → 4s → 8s → 10s (plafond). Mode DEGRADED explicite tant qu'indisponible.
Invariant couvert : INV-293-02
Point critique : C3 est l'unique point de communication avec les Ringbearers. C5 ne doit jamais contourner C3. L'implémentation réelle appelle claude-peers-mcp via MCP tools ; le mock (pour tests) simule via fichiers JSON temporaires.
Tests ciblés : TC-ERR-06, TC-ERR-10
Agent 4 : agent-persistence → C4 persistence¶
Fichier : scripts/lib/lord-persistence.sh
Mission : CRUD .gov-lord-state.json (schema §5.4), FIFO escalades, cache idempotency, audit JSONL.
Interfaces contractuelles : - lord_state_read() / lord_state_write(json) — écriture atomique (tmp + mv) + flock - lord_count_active_stories() → integer (stories non-terminales) - lord_create_story(story_id, project_code, state, peer_id) / lord_update_story(story_id, updates) / lord_get_story(story_id) - lord_enqueue_escalade(story_id, escalade_id, text, timestamp) — append FIFO - lord_dequeue_oldest_escalade(story_id) — retire le plus ancien OPEN de la story - lord_count_open_escalades(story_id) → integer - lord_check_idempotency(key, payload_hash) → NEW | REPLAY(result_hash) | CONFLICT - lord_record_idempotency(key, command, story_id, payload_hash, result_hash, ttl) - lord_purge_expired_idempotency() → count_purged
Décisions clés : - Fichier .gov-lord-state.json à la racine du repo (état runtime global, .gitignore) - Audit .gov-lord-audit.jsonl — jamais de escalade_text brut (RGPD), seulement escalade_id - Hash idempotency : sha256sum sur arguments normalisés - Valeur sentinelle "pending-{story_id}" pour peer_id en STARTING (H-TECH-09) - jq obligatoire (H-TECH-05) pour toute manipulation JSON
Invariants couverts : INV-293-13 (FIFO), INV-293-12 (idempotency), INV-293-04 (quota via count)
Tests ciblés : TC-NOM-02, TC-NOM-08, TC-NOM-13, TC-ERR-01, TC-ERR-08, TC-ERR-11
Pièges d'implémentation : - mv atomique uniquement si même filesystem → .tmp dans le même répertoire - flock autour des write pour protéger supervision loop vs commandes CLI concurrentes - Purge idempotency au démarrage ET opportuniste à chaque cycle
Wave 3 — Orchestrateur (séquentiel, dépend de C1+C2+C3+C4)¶
Agent 5 : agent-orchestrator → C5 orchestrator¶
Fichier : scripts/gov-lord.sh
Mission : Logique métier des 7 commandes, boucle de supervision, réconciliation, détection crash.
Interfaces contractuelles : - lord_start(story_id, project_code, idempotency_key) — gardes : quota → idempotence → format → doublon story - lord_status(story_id?) — consolidation C4 + C3 - lord_escalade(story_id?) — affichage file FIFO - lord_respond(story_id, response_text, idempotency_key) — gardes : idempotence → format - lord_pause(story_id, reason?, idempotency_key) / lord_resume(story_id, idempotency_key) / lord_stop(story_id, reason?, idempotency_key) - lord_supervision_loop() — boucle infinie avec sleep $interval & wait $! (trap-safe)
Boucle de supervision (chaque cycle) : 1. Vérifier broker status 2. Lister peers observés 3. Pour chaque story non-terminale : vérifier liveness / missed_polls / messages entrants 4. Réconciliation état local vs peers observés (INV-293-11) 5. Traitement messages (ESCALADE, WORKFLOW_DONE, STATUS_UPDATE, GATE_RESULT) 6. Purge idempotency expirée
Règle multi-escalade : transition ESCALADED→RUNNING uniquement quand toutes les escalades OPEN de la story sont traitées (lord_count_open_escalades == 0).
Invariants couverts : INV-293-01, INV-293-08, INV-293-11, INV-293-14
Pièges : - sleep N & wait $! pour réactivité SIGINT/SIGTERM - Lancement Ringbearer : unset CLAUDECODE && /Users/loic/.local/bin/claude -p "/gov PD-XX projet" & - Aucun import de jira-api.sh, state.sh ou module /gov existant
Wave 4 — Interface + Tests (parallélisables)¶
Agent 6 : agent-skill → C6 commands¶
Fichier : .claude/commands/gov-lord.md
Mission : Skill Claude Code /gov-lord — parsing arguments CLI, dispatch vers C5, whitelist 7 commandes.
Commandes :
/gov-lord start <story_id> <project_code> [--idempotency-key <key>]
/gov-lord status [--story <story_id>]
/gov-lord escalade [--story <story_id>]
/gov-lord respond <story_id> <réponse> [--idempotency-key <key>]
/gov-lord pause <story_id> [--reason <texte>] [--idempotency-key <key>]
/gov-lord resume <story_id> [--idempotency-key <key>]
/gov-lord stop <story_id> [--reason <texte>] [--idempotency-key <key>]
Toute autre commande → message de blocage explicite : "Commande non reconnue. Commandes disponibles: start, status, escalade, respond, pause, resume, stop"
Invariant couvert : INV-293-01, CA-05
Agent 7 : agent-tests → C7 tests¶
Fichiers : tests/lord/**/*.bats + tests/lord/mocks/** + tests/lord/fixtures/**
Mission : Suites BATS couvrant tous les TC-* contractuels.
Structure :
tests/lord/
helpers/ # setup/teardown, mock broker, fixtures loader
mocks/ # mock-broker.sh (simule list_peers, send_message, get_messages)
fixtures/ # JSON fixtures (.gov-lord-state.json préremplis par scénario)
state-machine.bats # TC-INV-01, TC-INV-02 (matrice 8×8)
validator.bats # TC-NOM-10, TC-ERR-03, TC-NEG-01..10
persistence.bats # TC-NOM-02, TC-NOM-08, TC-NOM-13, TC-ERR-01, TC-ERR-08, TC-ERR-11
orchestrator.bats # TC-NOM-01, TC-NOM-03..06, TC-NOM-07, TC-NOM-09, TC-NOM-12, TC-NOM-14
integration.bats # TC-ERR-02, TC-ERR-04..07, TC-ERR-09..10, TC-INV-03
negative.bats # TC-NEG-01..10 (validation dédiée)
non-regression.bats # TC-NR-01..04
Mock broker : Fonctions shell simulant lord_broker_* via fichiers JSON temporaires. Permet l'injection de scénarios (peer absent, broker DOWN, messages entrants).
Couverture : 40+ tests contractuels + additionnels pour ≥ 80%.
Matrice de couverture Test-ID → fichier de test¶
| Test ID | Fichier BATS |
|---|---|
| TC-INV-01, TC-INV-02 | state-machine.bats |
| TC-NOM-10, TC-ERR-03, TC-NEG-01..10 | validator.bats + negative.bats |
| TC-NOM-02, TC-NOM-08, TC-NOM-13, TC-ERR-01, TC-ERR-08, TC-ERR-11 | persistence.bats |
| TC-NOM-01, TC-NOM-03..06, TC-NOM-07, TC-NOM-09, TC-NOM-12, TC-NOM-14 | orchestrator.bats |
| TC-ERR-02, TC-ERR-04..07, TC-ERR-09..10, TC-INV-03 | integration.bats |
| TC-NR-01..04 | non-regression.bats |
| TC-MAN-01 | Manuel (hors BATS) |
Prérequis d'installation (vérification au démarrage C5)¶
| Dépendance | Commande de vérification | Installation |
|---|---|---|
| Bash 5.x | bash --version \| grep -q "version 5" | brew install bash |
| jq | command -v jq | brew install jq |
| GNU grep (-P) | echo "test" \| grep -P "\w" 2>/dev/null | brew install grep |
| bats-core | command -v bats | brew install bats-core |
| claude-peers-mcp | Vérifier MCP config | H-293-01 |
Fichiers à créer (aucune modification d'existant)¶
| Fichier | Agent | Nouveau |
|---|---|---|
scripts/lib/lord-state-machine.sh | agent-fsm | ✓ |
scripts/lib/lord-validator.sh | agent-validator | ✓ |
scripts/lib/lord-broker.sh | agent-broker | ✓ |
scripts/lib/lord-persistence.sh | agent-persistence | ✓ |
scripts/gov-lord.sh | agent-orchestrator | ✓ |
.claude/commands/gov-lord.md | agent-skill | ✓ |
tests/lord/** | agent-tests | ✓ |
.gov-lord-state.json | runtime (C4) | ✓ (.gitignore) |
.gov-lord-audit.jsonl | runtime (C4) | ✓ (.gitignore) |
Vérification INV-293-07 : Aucun fichier existant du workflow /gov n'est modifié par PD-293.