Taxonomie des opérateurs Caméléon

Version : v3 — 07/03/2026 Auteurs : O. Cugnon de Sévricourt · Léa (Recherche)


Principe de classification

Chaque opérateur est défini par une famille et zéro à trois attributs orthogonaux.

La famille est structurelle — elle découle de la topologie (ports, firing policy). Les attributs sont orthogonaux à la famille — ils décrivent le comportement au runtime.


Deux familles

Structurel

Contrôle de flux. Pas de logique métier, pas de transformation de données. La topologie dit tout — l'opérateur route, duplique, synchronise ou filtre.

Comportemental

Logique propre. Traitement de données, interaction, ou production de valeur.

Note terminologique — rapport à la littérature

La distinction Structurel / Comportemental est propre à Caméléon. Elle recouvre des distinctions analogues dans la littérature, sans leur être identique :

Ce qui est original dans Caméléon : les attributs orthogonaux human et live n'ont pas d'équivalent direct dans ces formalismes. human rejoint partiellement le concept de human task dans YAWL et les resource patterns (Russell et al., 2006), mais avec une sémantique plus précise (bloquant + validation unique). live est une contribution originale — ancré dans les open nets (Lohmann et al., 2007) et les langages réactifs synchrones (Caspi et al., 1987), mais inexistant comme attribut d'opérateur dans YAWL, BPMN ou LangChain.

Ces écarts terminologiques sont à documenter explicitement dans le paper v2 — ils ne sont pas des faiblesses mais des contributions.

Références - van der Aalst, W.M.P., ter Hofstede, A.H.M., Kiepuszewski, B., & Barros, A.P. (2003). Workflow Patterns. Distributed and Parallel Databases, 14(3), 5–51. - van der Aalst, W.M.P. & ter Hofstede, A.H.M. (2005). YAWL: Yet Another Workflow Language. Information Systems, 30(4), 245–275. - Russell, N., ter Hofstede, A.H.M., van der Aalst, W.M.P., & Mulyar, N. (2006). Workflow Control-Flow Patterns: A Revised View. BPM Center Report BPM-06-22. - OMG (2011). Business Process Model and Notation (BPMN) 2.0. - Lohmann, N., Massuthe, P., & Wolf, K. (2007). Operating Guidelines for Finite-State Services. TACAS 2007, LNCS 4424. - Caspi, P. et al. (1987). Lustre: A Declarative Language for Programming Synchronous Systems. POPL 1987.


Trois attributs orthogonaux

AttributSignificationComposition
configL'opérateur a des paramètres statiques définis avant le runFermée
humanBloque le flux pendant le run — attend une validation humaineFermée
liveInjecte en continu sur événement utilisateurOuverte

Un opérateur sans attribut s'exécute automatiquement, sans config ni interaction. Les attributs sont cumulables — un opérateur peut être config + human. La présence de live dans une composition la rend ouverte (ADR-035).


Catalogue des opérateurs

Structurels

OpérateurPortsFiringAttributsRôle
Fork1→NANYDuplique une donnée vers N sorties. addPlug() pour N>2
MergeN→1CONDXOR-join — ∃ input NEW, EMPTY ignoré. Pièce maîtresse des boucles
BarrierN→NALLBarrière — attend que toutes les entrées soient NEW simultanément
Switch1+1→NCONDRoute selon un index dans les données (in_data + in_index). addPlug() pour N>2
Gate1+1→2CONDAlias Switch(N=2) — in_condition: DataBoolout_true / out_false
Filter1→2CONDconfigRoute selon un prédicat défini en config — out_match / out_no_match
Router1→NCONDconfigRoute selon des prédicats multiples en config — premier vrai gagne. addPlug() pour N>2
Guard (backlog)1→2CONDconfigSort d'une boucle quand une condition config est remplie

Comportementaux

OpérateurPortsFiringAttributsRôle
Source0→NSpécialconfigProduit une valeur statique au démarrage (fire si sorties EMPTY)
FileLoader0→NSpécialhumanCharge un fichier sélectionné par l'utilisateur au démarrage — fire once
HumanInputN→MANYhumanBloque le flux et attend une saisie humaine validée
LiveSource0→NEnvironnementliveInjecte une valeur à chaque événement utilisateur — ouvre la composition
ProcessorN→MANYconfigTransformation générique — logique définie en config ou dans run()
AccumulatorN→MANYconfigTraitement par lot — accumule avant de produire
SinkN→0ANYConsomme ou termine un flux — déclenche la fin explicite si terminal

Règle de tir par défaut

ANY + garde EMPTY : tire dès qu'au moins une entrée est NEW, à condition qu'aucune ne soit EMPTY.

Au premier passage, l'opérateur attend que toutes ses entrées aient reçu une donnée. Ensuite il devient réactif — tire dès qu'un input est rafraîchi (NEW), même si les autres sont OLD. C'était le comportement de l'implémentation C++/QT originale.

Les trois firing policies

PolicyConditionOpérateurs
ANYAu moins 1 NEW, aucun EMPTYDéfaut — Processor, Fork, Sink, Accumulator, HumanInput
ALLToutes les entrées NEWBarrier
CONDSous-ensemble spécifique (délégué à l'opérateur)Switch, Gate, Filter, Router, Guard, Merge

Source : fire si toutes les sorties sont EMPTY. LiveSource : fire sur user_event() — transition d'environnement (ADR-035).


canFire() — Template Method sur l'opérateur

Le moteur appelle op.canFire(), point. La règle est portée par l'opérateur.


// Défaut ANY + garde EMPTY
const Operator = {
  canFire(inputStates, outputStates) {
    if (inputStates.some(s => s === "EMPTY")) return false;
    return inputStates.some(s => s === "NEW");
  }
};

// Overrides
Merge.canFire   = (ins) => ins.some(s => s === "NEW");  // XOR-join — EMPTY ignored
Barrier.canFire = (ins) => ins.every(s => s === "NEW");
Switch.canFire = (ins) => ins.in_data === "NEW" && ins.in_index === "NEW";
Gate.canFire   = (ins) => ins.in_data === "NEW" && ins.in_condition === "NEW";
Filter.canFire = (ins) => ins.in_data === "NEW";
Source.canFire = (ins, outs) => outs.every(s => s === "EMPTY");
// LiveSource : eop = user_event() — géré par le renderer (ADR-035)

Boucles


Modes d'exécution

ModeComportement
Séquentiel (actuel)Un seul opérateur tire par step
Concurrent (backlog)Tous les fireable tirent simultanément
RéactifDéclenché par la présence de LiveSource — dérivé de la topologie, pas de config

Signature type


// Structurel — pas de config, pas d'attribut
{
  id:           "fork",
  family:       "structural",
  firingPolicy: "ANY",
  inputs:       [{ id: "in", type: "Any" }],
  outputs:      [{ id: "out_0", type: "Any" }, { id: "out_1", type: "Any" }],
  run(inputs) { return { out_0: inputs.in, out_1: inputs.in }; }
}

// Comportemental avec config
{
  id:           "processor_example",
  family:       "behavioral",
  attributes:   ["config"],
  inputs:       [{ id: "in_a", type: "DataString" }],
  outputs:      [{ id: "out_a", type: "DataString" }],
  run(inputs, { config }) {
    return { out_a: transform(inputs.in_a, config) };
  }
}

// Comportemental avec human
{
  id:           "human_input",
  family:       "behavioral",
  attributes:   ["human"],
  control:      "text_input_control",
  inputs:       [{ id: "in_context", type: "Any" }],
  outputs:      [{ id: "out_value", type: "DataString" }],
  run(inputs, { signal }) {
    return new Promise((resolve, reject) => {
      signal?.addEventListener("abort", () => reject(new Error("cancelled")))
    })
  }
}

// Comportemental avec live — ouvre la composition
{
  id:           "live_source",
  family:       "behavioral",
  attributes:   ["live"],
  control:      "live_input_control",
  inputs:       [],
  outputs:      [{ id: "out_data", type: "Any" }],
  run(inputs, { signal }) {
    return new Promise((resolve, reject) => {
      signal?.addEventListener("abort", () => reject(new Error("cancelled")))
    })
  }
}

Correspondance Workflow Patterns (van der Aalst et al.)

Source : Russell, N., ter Hofstede, A.H.M., van der Aalst, W.M.P., & Mulyar, N. (2006). Workflow Control-Flow Patterns: A Revised View. BPM Center Report BPM-06-22.

Légende

StatutSignification
✅ NatifCouvert directement par un opérateur ou une connexion
🔶 ComposableCouvert par combinaison de primitives existantes
🔴 ManquantNon couvert — implémentation requise

Groupe 1 — Basic Control Flow (WCP 1–5)

WCPNomStatutOpérateur(s)Note
WCP-1Sequence✅ NatifConnexionToute connexion A→B est une séquence
WCP-2Parallel Split✅ NatifFork1→N, ANY
WCP-3Synchronization✅ NatifBarrierN→N, ALL
WCP-4Exclusive Choice✅ NatifGate / SwitchGate = N=2, Switch = N>2
WCP-5Simple Merge✅ NatifMergeN→1, ANY

Groupe 2 — Advanced Branching and Synchronization (WCP 6–9)

WCPNomStatutOpérateur(s)Note
WCP-6Multi-Choice✅ NatifRouterPlusieurs sorties activables simultanément
WCP-7Structured Synchronizing Merge🔶 ComposableRouter + BarrierBarrier attend les branches activées par Router — nécessite connaissance statique des branches actives
WCP-8Multi-Merge✅ NatifMerge (ANY)Chaque token traité dès réception
WCP-9Structured Discriminator🔴 ManquantPolicy FIRST — premier opérateur qui répond gagne. Priorité haute pour les race LLM

Groupe 3 — Structural (WCP 10–11)

WCPNomStatutOpérateur(s)Note
WCP-10Arbitrary Cycles🔶 ComposableMerge + GuardGuard en backlog
WCP-11Implicit Termination✅ NatifDétection automatique Completed

Groupe 4 — Multiple Instance (WCP 12–15)

WCPNomStatutOpérateur(s)Note
WCP-12Multiple Instances without Synchronization🔴 ManquantFork dynamique N instances sans attente
WCP-13Multiple Instances with a Priori Design-Time Knowledge🔴 ManquantN connu à la conception
WCP-14Multiple Instances with a Priori Runtime Knowledge🔴 ManquantN connu au runtime
WCP-15Multiple Instances without a Priori Runtime Knowledge🔴 ManquantN inconnu — génération à la volée

WCP 12–15 forment le cluster MapReduce. Priorité haute pour les workflows IA.

Groupe 5 — State-Based (WCP 16–18)

WCPNomStatutOpérateur(s)Note
WCP-16Deferred Choice🔶 ComposableLiveSource + GateL'environnement choisit la branche — composition ouverte requise
WCP-17Interleaved Parallel Routing🔴 ManquantN activités en ordre quelconque, jamais simultanées — mutex implicite
WCP-18Milestone🔴 ManquantActivité conditionnée à l'état d'une autre — nécessite observation d'état global

Groupe 6 — Cancellation and Force Completion (WCP 19–24)

WCPNomStatutOpérateur(s)Note
WCP-19Cancel Activity🔴 ManquantSignal CANCEL ciblé sur une activité — backlog
WCP-20Cancel Case🔶 ComposableStop globalStop annule la composition entière
WCP-21Structured Loop🔶 ComposableMerge + GuardGuard en backlog
WCP-22Recursion🔴 ManquantComposition récursive — hors modèle CVM actuel
WCP-23Transient Trigger🔶 ComposableLiveSourceSignal externe one-shot — last-write-wins approche ce comportement
WCP-24Persistent Trigger✅ NatifLiveSourceSignal externe persistant — sémantique naturelle de LiveSource

Groupe 7 — Advanced Cancellation (WCP 25–27)

WCPNomStatutOpérateur(s)Note
WCP-25Cancel Region🔴 ManquantAnnuler un sous-graphe délimité — nécessite notion de région
WCP-26Cancel Multiple Instance Activity🔴 ManquantDépend de WCP 12–15
WCP-27Complete Multiple Instance Activity🔴 ManquantDépend de WCP 12–15

Groupe 8 — Advanced Synchronization (WCP 28–36)

WCPNomStatutOpérateur(s)Note
WCP-28Blocking Discriminator🔴 ManquantPremier arrivé gagne, les autres bloqués jusqu'à reset
WCP-29Cancelling Discriminator🔴 ManquantPremier arrivé gagne, les autres annulés
WCP-30Structured Partial Join🔴 ManquantAttendre M parmi N branches (M statique)
WCP-31Blocking Partial Join🔴 ManquantM parmi N, retardataires bloqués
WCP-32Cancelling Partial Join🔴 ManquantM parmi N, retardataires annulés
WCP-33Generalised AND-Join🔶 ComposableBarrier (ALL)Version standard couverte — tolérance aux branches mortes manquante
WCP-34Static Partial Join for Multiple Instances🔴 ManquantDépend de WCP 12–15
WCP-35Cancelling Partial Join for Multiple Instances🔴 ManquantDépend de WCP 12–15
WCP-36Dynamic Partial Join for Multiple Instances🔴 ManquantDépend de WCP 12–15

Groupe 9 — Structural (WCP 37–38)

WCPNomStatutOpérateur(s)Note
WCP-37Acyclic Synchronizing Merge🔶 ComposableRouter + BarrierMême contrainte que WCP-7
WCP-38General Synchronizing Merge🔴 ManquantVersion acyclique et cyclique — nécessite observation d'état dynamique

Groupe 10 — Instance Patterns (WCP 39–43)

WCPNomStatutOpérateur(s)Note
WCP-39Critical Section🔴 ManquantMutex entre sous-graphes — mode concurrent requis
WCP-40Interleaved Routing🔴 ManquantVersion non-structurée de WCP-17
WCP-41Thread Merge🔴 ManquantFusionne des threads — mode concurrent requis
WCP-42Thread Split🔴 ManquantCrée des threads — mode concurrent requis
WCP-43Explicit Termination✅ NatifSinkFin explicite déclenchée par un Sink terminal

Récapitulatif

StatutNombreWCP
✅ Natif101, 2, 3, 4, 5, 6, 8, 11, 24, 43
🔶 Composable97, 10, 16, 20, 21, 23, 33, 37
🔴 Manquant249, 12, 13, 14, 15, 17, 18, 19, 22, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 38, 39, 40, 41, 42

Couverture (natif + composable) : 19/43 — 44 %

Clusters manquants

ClusterPatternsPriorité
MapReduceWCP 12–15, 26, 27, 34, 35, 36Haute — workflows IA multi-LLM
Discriminator / Partial JoinWCP 9, 28–32Haute — race LLM (WCP-9 seul suffit à court terme)
Cancel cibléWCP 19, 25Moyenne — un signal CANCEL sur région couvre les deux
ConcurrentWCP 17, 39, 40, 41, 42Bloqué par mode séquentiel actuel
DiversWCP 18, 22, 38Basse — complexité élevée, cas rares

Historique des décisions

DateDécision
02-03/03/2026Termes validés par O. Cugnon de Sévricourt
03/03/2026"structurel" remplace "generics" (ancien terme C++/QT)
03/03/2026Merge, Barrier (ex-Sync) confirmés dans l'implémentation C++/QT originale
03/03/2026Défaut ANY + garde EMPTY confirmé
03/03/2026Correspondance WCP validée
03/03/2026canFire() = méthode sur l'opérateur avec override
05/03/2026HumanInput — attribut human (ADR-034)
05/03/2026LiveSource — attribut live, transition d'environnement (ADR-035)
05/03/2026Distinction compositions fermées / ouvertes (ADR-035)
06/03/2026Gate = Switch(N=2) alias booléen. Switch avec addPlug()
06/03/2026Filter et Router ajoutés — attribut config
06/03/2026FileLoader ajouté — attribut human, fire once au démarrage
07/03/2026Deux familles : Structurel / Comportemental — terminologie propre à Caméléon, volontairement distincte de Gateway/Task (BPMN) et routing construct/activity node (van der Aalst). Structurel = on structure le flux. Comportemental = il se passe quelque chose. Culture produit.
07/03/2026Trois attributs orthogonaux : config / human / live
07/03/2026Data-driven vs Config-driven retiré comme axe formel — conséquence naturelle de l'attribut config
07/03/2026Correspondance complète 43 WCP intégrée
07/03/2026Sync renommé Barrier — plus explicite : décrit ce que l'opérateur fait (barrière de synchronisation)