Darkwood Blog Blog
  • Articles
  • Veille
  • Releases
  • CrĂ©ateurs
fr
  • de
  • en
Connexion
  • Blog
  • Articles
  • Veille
  • Releases
  • CrĂ©ateurs

đŸ’» L'ordinateur portable, dernier goulot d'Ă©tranglement : des agents de codage aux flux de travail partagĂ©s

le 26 juillet 2026

Connectez-vous pour réagir à cet article

🚀 1

Un seul agent de codage dans un terminal est gĂ©rable. On lui demande de modifier un fichier, on jette un coup d'Ɠil aux diffĂ©rences, on exĂ©cute les tests dont on se souvient, et on passe Ă  autre chose. La liste de vĂ©rification invisible tient toujours dans une seule tĂȘte.

Ensuite, vous ouvrez un deuxiÚme agent. Puis un troisiÚme. L'un travaille sur l'API. Un autre réécrit la documentation. Un troisiÚme effectue un test de sécurité. Soudain, vous ne faites plus que programmer. Vous planifiez, vous vérifiez et vous vous souvenez. Cette exécution a-t-elle inclus une analyse statique ? Cette branche a-t-elle fait l'objet d'un contrÎle de sécurité ? Que nous a appris l'échec d'hier que cette discussion a déjà oublié ?

Les agents ne sont pas nĂ©cessairement incompĂ©tents. Le processus qui les entoure reste personnel. Telle est la thĂšse de cet article, Ă©tayĂ©e par une petite expĂ©rience PHP : exposer une checklist de « revue des changements » d’ingĂ©nierie sous forme d’API HTTP avec Framework X comme environnement d’exĂ©cution asynchrone et Darkwood Flow comme couche d’orchestration.

L'idée technique centrale est simple :

Le framework X reçoit et exĂ©cute les requĂȘtes. Le flux dĂ©crit et coordonne le travail dĂ©clenchĂ© par ces requĂȘtes.

Ce ne sont pas des concurrents. Ils se situent Ă  diffĂ©rents niveaux d'un mĂȘme problĂšme.

Le flux de travail caché

Le dĂ©veloppement logiciel constitue dĂ©jĂ  un flux de travail, mĂȘme lorsque personne ne dessine les boĂźtes :

Change code
    ↓
Run tests
    ↓
Run static analysis
    ↓
Review security
    ↓
Update documentation
    ↓
Review result

Quand cette procĂ©dure n'est qu'une habitude – « Je lance toujours PHPUnit avant de pousser » – elle est fragile. Un vendredi matin fatiguĂ©, on oublie une Ă©tape. Un nouveau collĂšgue ne l'a jamais apprise. Une conversation avec un agent, sortie de son contexte, est impossible Ă  reconstituer.

L'étape manquante n'est pas une invite plus intelligente. Il s'agit de rendre le processus explicite : nommer les étapes, les entrées et les sorties, les modes d'échec et conserver une trace de ce qui a été réellement exécuté.

Pourquoi l'ordinateur portable devient le goulot d'étranglement

Dire que « l'ordinateur portable est le goulot d'Ă©tranglement » peut facilement ĂȘtre interprĂ©tĂ© Ă  tort comme un problĂšme matĂ©riel. L'argument intĂ©ressant est d'ordre organisationnel.

L'ordinateur portable renferme bien plus qu'un simple processeur. Il contient l'identité et les identifiants, l'accÚs aux référentiels, les invites et compétences privées, les scripts locaux, la configuration du modÚle, l'historique des agents, les conventions du projet et les enseignements tirés des échecs de la semaine précédente. Il sert à la fois d'environnement d'exécution et de silo de connaissances.

Lorsque plusieurs agents travaillent en parallÚle, tout ce qui compense leurs limites reste personnel :

  • n'oubliez pas les tests, l'analyse statique, la sĂ©curitĂ©, la documentation, la revue, les contraintes de dĂ©ploiement ;
  • souvenez-vous de ce que les courses prĂ©cĂ©dentes ont appris ; — Conservez les secrets et les listes blanches sur une seule machine.

Cette solution n'est pas applicable à une équipe. Lorsque la personne (ou l'ordinateur portable) quitte l'entreprise, l'automatisation et sa mémoire disparaissent également.

Des commandes d'agent aux flux de travail

Le changement conceptuel s'opÚre à partir de :

Give one agent a large task

Ă :

Define a sequence of bounded steps

Chaque étape peut ensuite consister en du code PHP, une commande shell, un appel API, un agent de codage, un autre modÚle, une validation humaine ou le déploiement d'un service. Dans l'expérience décrite ci-dessous, les étapes sont volontairement des services PHP locaux déterministes. L'important est la structure du processus, et non une simple démonstration de maßtrise en langage naturel.

Le flux de travail constitue la couche durable. Le modÚle ou l'agent actuel est remplaçable.

L'expérience Framework X

Le prototype se trouve dans un petit projet, framework-x-flow. Ce n'est pas un produit. C'est un laboratoire pour une question : pouvons-nous transformer une liste de contrÎle d'ingénierie privée en quelque chose de visible, inspectable et reproductible via HTTP, sans prétendre avoir construit une plateforme d'agent cloud ?

Architecture en un seul diagramme :

HTTP request
    ↓
Framework X route + middleware
    ↓
Flow workflow (jobs over Ip payloads)
    ↓
Steps (validate → analyse → quality → docs → review → retrospective)
    ↓
Trace + retrospective
    ↓
JSON response (+ atomic file under var/runs/)

RĂ©partition des responsabilitĂ©s, telle que mise en Ɠuvre :

Préoccupation Framework X Darkwood Flow Cette démo
RequĂȘtes HTTP / routage Oui Non Gestionnaires
Serveur ReactPHP Ă  longue durĂ©e de vie Oui (HttpServerRunner) IntĂ©grĂ© via un pilote —
Définition du flux de travail Non Oui (tùches FlowFactory) Chaßne de révision des modifications
Exécution des étapes Niveau gestionnaire uniquement Oui (tùches / adresses IP) Classes d'étapes
Contexte du flux de travail Attributs de la requĂȘte Pipeline de donnĂ©es Ip ChangeReviewContext
Primitives asynchrones Promesses, générateurs, fibres Pilotes (ReactDriver, FiberDriver, 
) Adaptateur EmbeddedReactDriver
Concurrence IP — MaxIpStrategy ExpĂ©rimentation CLI / HTTP
ContrĂŽles qualitĂ© parallĂšles intra-exĂ©cution — DAG non natif Adaptateur Promise::all pour ReactPHP
Persistance des exécutions / traces Journaux d'accÚs Pas de stockage d'exécution de premier ordre Fichiers JSON + traces d'étapes
Erreurs JSON sĂ©curisĂ©es Erreurs HTML 500 par dĂ©faut — JsonErrorHandler
Bac à sable sécurisé Non Non Non

Comment fonctionne le Framework X (juste ce qu'il faut)

Framework X (clue/framework-x, actuellement 0.17.x) est un microframework basĂ© sur ReactPHP. Une mĂȘme App peut fonctionner comme un serveur HTTP CLI persistant ou derriĂšre une API PHP traditionnelle.

Le choix du runner est compatible avec SAPI : en ligne de commande, HttpServerRunner Ă©tablit une connexion socket (par dĂ©faut 127.0.0.1:8080, modifiable avec X_LISTEN) et exĂ©cute la boucle d'Ă©vĂ©nements de ReactPHP ; derriĂšre FPM ou Apache, SapiRunner traite une requĂȘte provenant des variables globales. Pour les tests et l'intĂ©gration, App::__invoke() traite une seule requĂȘte PSR-7 et attend la rĂ©solution des promesses.

Les gestionnaires peuvent renvoyer une rĂ©ponse PSR-7 synchrone, une PromiseInterface ou un gĂ©nĂ©rateur de promesses. Sous PHP 8.1 et versions ultĂ©rieures en mode CLI, HttpServerRunner encapsule Ă©galement chaque requĂȘte dans un FiberHandler, permettant ainsi Ă  React\Async\await() de paraĂźtre synchrone sans perturber la comprĂ©hension du code. Les erreurs sont conçues pour ĂȘtre traitĂ©es comme des rĂ©ponses HTTP et non pour interrompre le processus : ErrorHandler normalise les exceptions, les promesses rejetĂ©es et les types de retour invalides.

L'injection de dépendances est un petit Conteneur : configuration de tableau, fabriques, paramÚtres de type ENV, PSR-11 optionnel. Les contrÎleurs de classe-chaßne sont résolus de maniÚre paresseuse.

C’est pourquoi Framework X est important pour cet article : il permet d’exposer des flux de travail via HTTP et de maintenir un processus asynchrone actif. Il ne s’agit ni d’un planificateur, ni d’une file d’attente, ni d’un environnement d’exĂ©cution mutualisĂ©, ni d’un moteur d’exĂ©cution d’agent.

Il prĂ©sente Ă©galement des imperfections qu'il convient de mentionner. Le gestionnaire d'erreurs par dĂ©faut intĂšgre systĂ©matiquement la classe d'exception, le message et l'emplacement du fichier dans le corps des rĂ©ponses 500 HTML ; il n'existe pas d'option pour passer du mode dĂ©bogage au mode production. Le gestionnaire de routes conserve son propre chemin d'accĂšs aux erreurs 404/405 HTML. Le package est encore en version 0.x. Un processus CLI de longue durĂ©e partage la mĂ©moire entre les requĂȘtes : les singletons mutables, les appels bloquants et les Loop::stop() imbriquĂ©s sont des piĂšges. Un environnement d'exĂ©cution asynchrone ne rend pas le PHP bloquant non bloquant ; sleep(), les clients HTTP synchrones et les opĂ©rations importantes sur le systĂšme de fichiers continuent de bloquer la boucle.

Comment Flow s'adapte

Darkwood Flow (darkwood/flow v8.1.1, PHP ≄ 8.5) est un pipeline de tĂąches basĂ© sur des pilotes. Vous crĂ©ez une chaĂźne avec FlowFactory::create(), y insĂ©rez des tĂąches sous forme de valeurs Ip et appelez await() jusqu'Ă  ce que le flux soit vidĂ©. Chaque tĂąche reçoit $ip->data et renvoie la valeur de donnĂ©es suivante. En cas d'Ă©chec, une exception Flow\Exception\RuntimeException est levĂ©e ; une tĂąche errorJob optionnelle est alors exĂ©cutĂ©e Ă  chaque Ă©tape, et le pipeline s'interrompt Ă  l'Ă©tape suivante.

Dans la dĂ©mo, le flux de travail de rĂ©vision des modifications est assemblĂ© Ă  peu prĂšs comme ceci (les fermetures encapsulent les objets d'Ă©tape invocables — Flow accepte Closure|JobInterface, et non des objets invocables nus) :

return (new FlowFactory($driver))->create(static function () use (
) {
    yield [static fn (ChangeReviewContext $ctx) => $validate($ctx), $errorJob];
    yield [static fn (ChangeReviewContext $ctx) => $analyse($ctx), $errorJob];
    // concurrent quality adapter, or sequential tests / static / security stages
    yield [static fn (ChangeReviewContext $ctx) => $docs($ctx), $errorJob];
    yield [static fn (ChangeReviewContext $ctx) => $final($ctx), $errorJob];
    yield [static fn (ChangeReviewContext $ctx) => $retro($ctx), $errorJob];
}, ['driver' => $driver]);

Étapes conceptuelles :

validate
    ↓
analyse
    ↓
tests | static-analysis | security-review
    ↓
documentation
    ↓
final-review
    ↓
retrospective

Surface HTTP (routes Framework X) :

$app->get('/health', HealthHandler::class);
$app->get('/workflows/change-review', DescribeWorkflowHandler::class);
$app->post('/workflows/change-review/runs', RunWorkflowHandler::class);
$app->get('/workflows/change-review/runs/{runId}', GetWorkflowRunHandler::class);
$app->get('/analysis/framework-x-flow', AnalysisHandler::class);
$app->get('/experiments/sequential-vs-concurrent', ExperimentHandler::class);

Ce que Flow fournit : chaßnes de tùches, adresses IP, pilotes, stratégies telles que MaxIpStrategy et hooks errorJob.

Ajouts de la dĂ©mo : reprĂ©sentation HTTP, identifiants d'exĂ©cution, suivi du temps d'exĂ©cution, persistance atomique JSON sous var/runs/, formatage rĂ©trospectif, indicateurs d'Ă©chec contrĂŽlĂ©s et, surtout, un EmbeddedReactDriver. La fonction native Flow\Driver\ReactDriver::await() appelle Loop::run() et Loop::stop(). Le HttpServerRunner du framework X gĂšre dĂ©jĂ  la boucle ; appeler la fonction native await() dans une requĂȘte arrĂȘterait le serveur HTTP. Le pilote intĂ©grĂ© conserve la sĂ©mantique asynchrone/de dĂ©lai de React, mais rĂ©sout une promesse sans interrompre la boucle partagĂ©e. Cet adaptateur fait partie du code du projet et n'est pas intĂ©grĂ© Ă  Flow.

Le mode qualitĂ© par dĂ©faut regroupe trois vĂ©rifications dans une seule tĂąche Flow via Promise::all de ReactPHP (ConcurrentQualityChecksStep). Il s'agit Ă©galement d'un adaptateur. Le modĂšle de concurrence natif de Flow repose sur plusieurs IP au sein d'une mĂȘme Ă©tape avec MaxIpStrategy, et non sur un DAG parallĂšle d'Ă©tapes enfants au sein d'une seule IP.

Exécution séquentielle versus simultanée

L'expérience en ligne de commande (php bin/experiment) compare trois adresses IP, chacune avec un délai de 0,05 s :

Mode Stratégie Temps écoulé observé (local, 2026-07-26)
Séquentiel MaxIpStrategy(1) 152,446 ms
Concurrent MaxIpStrategy(3) 50,088 ms
AccĂ©lĂ©ration — ~3,04×

Ces durées sont données à titre indicatif et ne constituent pas une valeur scientifique. Elles correspondent à la forme attendue : trois retards successifs contre trois retards qui se chevauchent.

Une observation subtile : LinearIpStrategy seule provoque toujours des chevauchements entre les tùches asynchrones sous ReactDriver, car la boucle de récupération peut démarrer l'IP suivante pendant que la tùche précédente est en cours. Un véritable contrÎle séquentiel est nécessaire avec MaxIpStrategy(1). C'est le genre de détail qui ne se révÚle qu'aprÚs des mesures.

La concurrence n'est utile que lorsque les tùches sont indépendantes et non bloquantes. Encapsuler une tùche bloquante dans une promesse ne libÚre pas la boucle d'événements.

L'échec fait partie du flux de travail

L'orchestration ne se limite pas Ă  l'ordonnancement des scĂ©narios nominaux. La dĂ©monstration accepte les indicateurs d'erreur contrĂŽlĂ©s dans le corps de la requĂȘte POST (exception, promise, async, security), rejette les JSON invalides avec un code 400 sĂ©curisĂ© et intĂšgre les Ă©checs d'Ă©tape dans un rapport d'exĂ©cution structurĂ©.

Étant donnĂ© que les erreurs par dĂ©faut du Framework X sont au format HTML et dĂ©taillĂ©es, l'application utilise un JsonErrorHandler qui Ă©tend ErrorHandler. Cette sous-classe est importante : un middleware simple placĂ© « en amont » reçoit toujours un ErrorHandler HTML standard, non modifiĂ© par l'initialisation de l'application. Le journal d'accĂšs, lorsqu'il est prĂ©sent, doit ĂȘtre immĂ©diatement suivi d'une instance de ErrorHandler. Les clients voient des codes tels que internal_error ou invalid_json ; les dĂ©tails sont consignĂ©s dans un fichier journal local.

Par exemple, un contrÎle de sécurité ayant échoué a généré un rapport contenant :

{
  "code": "quality_check_failed",
  "message": "Security check failed: no dependency audit result was supplied."
}

et s'est poursuivi suffisamment loin pour qu'une rĂ©trospective puisse proposer un changement concret de flux de travail — et non une simple trace de pile dans le navigateur.

L'étape rétrospective

La derniÚre tùche consiste à établir une rétrospective déterministe : étapes lentes, échecs de vérification, avertissements, enseignements et modifications suggérées du flux de travail. Concernant la faille de sécurité mentionnée ci-dessus, la proposition était la suivante :

{
  "target": "security-review",
  "reason": "The security check failed because no dependency audit result was supplied.",
  "proposal": "Add a dependency audit step before final review."
}

La note qui accompagne chaque rétrospective est intentionnelle :

Propositions uniquement — cette Ă©tape ne modifie pas le code de l'application ni les dĂ©finitions de flux de travail.

Proposer une modification du flux de travail ne revient pas Ă  le réécrire en catimini. Une amĂ©lioration continue et contrĂŽlĂ©e est prĂ©fĂ©rable Ă  une modification incontrĂŽlĂ©e. L'apprentissage automatique, la gĂ©nĂ©ration automatique de propositions et l'Ă©volution autonome de l'automatisation de la production sont trois concepts distincts ; ce prototype ne met en Ɠuvre que le concept intermĂ©diaire.

Ce que signifie réellement la migration vers le cloud

DĂ©ployer le mĂȘme script PHP sur un serveur ne constitue pas une collaboration. Une plateforme de gestion des flux de travail d'Ă©quipe nĂ©cessite une exĂ©cution partagĂ©e, un historique durable, la gestion des identitĂ©s et des permissions, l'isolation des secrets, un environnement isolĂ© (sandbox), une politique rĂ©seau, des quotas, l'auditabilitĂ©, le nettoyage et, souvent, des files d'attente ou une planification distribuĂ©e.

Les produits existants dans ce secteur – Upsun Dispatch, par exemple, s'inscrit dans le dĂ©bat plus large sur l'exĂ©cution d'agents Ă  distance – existent prĂ©cisĂ©ment parce que ces problĂšmes sont complexes. Mentionner ce contexte ne constitue en aucun cas une approbation d'un fournisseur. Pour Darkwood, l'objectif est plus prĂ©cis : l'orchestration (explorĂ©e par Flow) et l'hĂ©bergement sĂ©curisĂ© d'agents mutualisĂ©s (que ce prototype ne propose pas) sont deux couches distinctes. Framework X et Flow ne fournissent actuellement aucun environnement d'exĂ©cution sĂ©curisé ; affirmer le contraire serait faux.

Ce que ce prototype ne prouve pas

  • Aucun environnement de test sĂ©curisĂ© dans le cloud, aucun courtier d'identifiants ni aucune liste blanche de commandes.
  • Pas de planificateur distribuĂ© ni de file d'attente de messages durable.
  • Pas d'isolation multi-locataires ni de gouvernance d'Ă©quipe automatique.
  • Aucune modification autonome et sĂ©curisĂ©e des flux de travail.
  • Rien ne prouve que chaque tĂąche de codage doive devenir un flux de travail formel.
  • Aucune preuve que Framework X soit le seul ou le meilleur environnement d'exĂ©cution pour ce modĂšle.
  • Rien ne prouve que le simple fait d'encoder une liste de contrĂŽle sur un ordinateur portable en fasse automatiquement un flux de travail d'Ă©quipe — le partage nĂ©cessite toujours un dĂ©ploiement, un stockage partagĂ© et un processus social.

Cela montre qu'un rapport d'exĂ©cution explicite est plus facile Ă  examiner qu'une transcription de conversation privĂ©e, que les moteurs d'exĂ©cution asynchrones et les moteurs de flux de travail rĂ©solvent des problĂšmes diffĂ©rents, et que les adaptateurs honnĂȘtes (EmbeddedReactDriver, qualitĂ© concurrente via Promise::all) sont meilleurs que d'inventer des fonctionnalitĂ©s que les bibliothĂšques n'ont pas.

Conclusion

Les modĂšles vont Ă©voluer. Les agents de codage vont Ă©voluer. Les fournisseurs vont renommer les mĂȘmes problĂšmes d'infrastructure.

Ce qui reste utile, c'est le processus qu'une Ă©quipe peut nommer, exĂ©cuter, inspecter, dans lequel elle peut Ă©chouer en toute sĂ©curitĂ© et qu'elle peut amĂ©liorer intentionnellement : valider, analyser, vĂ©rifier la qualitĂ©, documenter, examiner, rĂ©trospectivement – ​​encodĂ© sous forme de donnĂ©es, et non sous forme de folklore sur un ordinateur portable.

Framework X peut ĂȘtre le point d'entrĂ©e de la requĂȘte. Flow peut ĂȘtre le graphe qui coordonne le travail. Aucun des deux ne remplace les aspects techniques de l'exĂ©cution d'un agent cloud. Ensemble, dans cette petite expĂ©rience, ils rendent la liste de contrĂŽle visible.

L'artefact utile n'est plus l'invite de commande privée. C'est le flux de travail que vous pouvez exécuter à nouveau demain et dont vous pouvez discuter dans une demande de fusion.

Connectez-vous pour réagir à cet article

🚀 1

Site

  • Plan du Site
  • Contact
  • Mentions lĂ©gales

Network

  • Hello
  • Blog
  • Apps
  • Photos

Social

Darkwood 2026, tous droits réservés