r-io suiter-io suitereference docs
← Documentation home
Reference / Models & DSL

The 2L language

2L is the small language written on the edges of the collaborative model. It says when a problem becomes active, where its zone lies and how probable it is, and it guards the links and flows of a deduced process: which task runs after another, when a corrective or a recovery starts. This page lists where 2L is used, its syntax, how rules and conditions are executed and every method, each with an example taken from a use case.

01 · Where 2L is used

Two kinds of code: rules and conditions

Every relation property of type code editor tagged RIO_2L in the collaborative metamodel holds 2L. A rule acts on the model (status, probability, position, zone); a condition answers true or false and never changes anything that is kept.

EdgePropertyKindEvaluated$source / $target
Rules — run by the 2L manager on the knowledge graph
Generated_Byactivation conditionruleIn a propagation wave, when a node the rule reads becomes or stays ACTIVESource and target of the edge, e.g. the generated problem and its generator (a sensor, an asset, a potential, a risk)
Is_Susceptible_Tosusceptibility conditionruleSameThe susceptible asset or role / the potentiality it is exposed to
Impactsimpacts conditionruleSameThe problem / the impacted asset, role or resource
Generatesgeneration conditionruleSameSource and target of the edge (no packaged use case fills it)
Conditions — property “Condition Evaluation”, evaluated by the PRIO workflow engine
Implies · Supports · NeedsCondition EvaluationconditionNever on the link itself: the deduction copies it onto the Sequence_Flows entering the guarded task, read once (see conditioned links)—
“Wait Until” Mediation functionWait ConditionconditionOn the task deduced from the function: when the wait starts, then every Wait Polling (s) (5 by default) until it is true; only its own branch waitsThe wait task / the task it leads to
Sequence_FlowCondition EvaluationconditionWhen the process leaves the source node of the flowThe node being left / the next node of the flow
Event_FlowCondition EvaluationconditionWhen the nominal sub-task starts, then every 5 s while it runs; fires at most onceThe nominal sub-task / the corrective sub-process
Exception_FlowCondition EvaluationconditionWhen the task starts, then every 5 s while a human task runsThe task / its recovery sub-process
$source and $target follow the edge, not a role

The two variables are bound to the actual source and target of the edge. Default Generated_By rules exist for both directions (actuality → potentiality and the reverse): before writing a rule, check on the diagram which node is the source.

02 · Syntax

A small subset of Java

The grammar is a reduced Java: declarations, if / else, for over a list, method calls, property reads and writes. There is no return, no while, no class nor method declaration.

Statements

What a line can be

  • a declaration: Node sensor = …;, Float radius = …;, List<Node> risks = …;, boolean ok = …;
  • a method call: $source.active();
  • a property write: risk.probability = 0.05;
  • if (…) { … } else { … }, nested at will
  • for (Node risk : risks) { … }
  • comments // and /* … */
Types

Declared, barely checked

Node, boolean, int, float, double and any name such as Float or String are accepted. Only List<…> matters: a list variable always holds a list (a single node is wrapped, nothing gives an empty list), and a scalar variable that receives a list keeps its first element.

Literals

Numbers are Float

Integers and decimals (1, 0.05) become 32-bit floats, so $target.probability == 1 works on a probability read as a float. Strings are double-quoted ("Yes and repairable"); true, false and null are available.

OperatorOperandsResult
== · !=anything; properties are converted first (see Values)value equality; null == null is true, x == null tests an absence
< · > · <= · >=numbersboolean; a null operand is an error in a rule
+two numbers, or two stringssum, or concatenation
- · * · /numbersfloat; division by zero is an error
&&booleansfalse as soon as the left side is false: the right side is still read (to know which nodes the rule watches) but its errors are ignored, so henri != null && henri.getGeoloc()… is safe
||booleanstrue as soon as the left side is true, same tolerance
! · unary -boolean · numbernegation
@variable[Function name]—value of a task variable at run time (see Conditions)

Not interpreted although the parser accepts them: %, ++ / --, the ternary ?:, casts and instanceof (use isInstanceOf("Concept")). Compound assignments (+=…) behave like a plain =. A local variable cannot be assigned again after its declaration: declare a new one. There are no parentheses in expressions: (a || b) && c does not parse; write intermediate boolean variables instead (boolean cleared = …; boolean reopen = cleared && riskLow;).

03 · Relation arrows

Following the edges, written as in Cypher

An arrow goes from a node to its neighbours through the edges of one relation, in the direction the edge is stored in the model. The former call form x.Relation("name") is no longer part of the language: the interpreter rejects it with an error that gives the arrow to write.

FormGives
a -[Rel]-> (Type "name")the nodes at the end of the Rel edges leaving a
a <-[Rel]- (Type "name")the nodes at the start of the Rel edges arriving at a
(Type) · ("name") · ()the pattern filters by concept (the concepts inheriting it match too) and by exact name, both optional
a -[Rel]-> b · a <-[Rel]- bwith an expression instead of a pattern: true when such an edge links a to the node b
a <-[Prevents]- ().active();a method call or a property read can follow the pattern, and a statement can start with an arrow

A traversal gives null when nothing matches, the node when one does, a list otherwise. Reference copies embedded in solutions are left out, as in findNodeInstance. An unknown relation or concept is an error.

From the packaged use casesarrows
Node sensor = $target <-[Fixed_Onto]- ("Loire water level - Orleans");   // Orléans: the sensor fixed onto the bridge
if($target <-[Fixed_Onto]- ("Barbecue thermal sensor").currentValue >= 50) { … }   // Barbecue
Node objectiveRiskBurns = riskBurns <-[Prevents]- ("Prevent Henri risks getting burned");
List<Node> risks = potential <-[Generated_By]- ();   // Healthcare: the risks generated by the potential
risk <-[Prevents]- ().active();
Node risk = objective -[Prevents]-> (Risk);            // crisis roles: the risk the objective prevents
Node flood = risk <-[Generated_By]- (Actuality);
Read the arrow as the edge

An objective prevents a risk with an edge objective –Prevents→ risk: from the objective it is objective -[Prevents]-> (Risk), from the risk risk <-[Prevents]- (). When the direction of an edge depends on who wrote it, test both arrows (see the Event_Flow example below).

04 · Values

What an expression yields

ExpressionValue
$source, $target, findNodeInstance(…)a node of the knowledge graph, or null
a -[Rel]-> (…), a <-[Rel]- (…)one node, a list or null; a -[Rel]-> b gives a boolean (see Relation arrows)
node.propertythe property of that name, converted when it is compared, computed or assigned: a metric (probability, currentValue…) gives its precise value as a float, a number property a float, any other property its text; null when the node has no such property
node.statusthe list of statuses of the node (prefer isActive() / isFreeze())
node.getGeoloc()the geolocation of the node (point, circle, polygons or lines)
geoloc.getPosition()a point: the point itself, the centre of the circle or the centroid of the polygons
geoloc.radiusthe radius of the circle, in metres
Maththe only built-in variable, for Math.random(min, max)

Only properties whose name is a valid identifier can be read with the dot (currentValue, probability, name). Writing a property (risk.probability = remaining / span;) updates a metric’s precise value or stores the text of the value; a property the node does not have is not created.

05 · Rules

How rules run: propagation waves

The rules of a knowledge space are registered when their edge is written (Code2L interceptor) and run again whenever the situation they read changes.

1 · Registration

A dry run finds what the rule watches

The rule is interpreted once in a read-only analysis: every node read inside an if condition or a for list is subscribed. active(), freeze(), positions and property writes are ignored during this pass. A rule whose nodes are not all known yet is analysed again later.

2 · Trigger

An ACTIVE node starts a wave

When a node is added or updated with the ACTIVE status (a sensor value, an activated problem…), the rules subscribed to it start a wave. An update to FREEZE alone starts nothing. Waves of the same knowledge space run one after the other.

3 · Fixpoint

Chained in memory, saved once

The rules are run in memory, then the rules of every node they changed, and so on until nothing changes (at most 25 passes; a node coming back to an earlier state stops the wave). A rule that fails is skipped without cancelling the others. The changed nodes are then published together, and the frozen objectives that treat, prevent or enable a problem that became active are activated in the same publish.

One waveLLManager.runFixpoint
workset = { seed node }                     # an ACTIVE node just added or updated
while workset not empty and pass < 25:
  for node in workset:
    for rule in rules watching node:
      run rule on the in-memory copies       # findNodeInstance sees the state computed by the other rules
      next += nodes it really changed        # same state as before: not a change
  stop if a node returns to an earlier state
  workset = next
publish changed nodes + objectives of the problems that became ACTIVE
06 · Conditions

How conditions are evaluated

A Condition Evaluation is a boolean expression, optionally preceded by declarations. It is evaluated by the PRIO engine when needed, never registered as a rule, and it never saves anything.

Shape

Statements, then an expression

The last statement gives the result: @Confirmed gas leak[Confirm gas leak] == "Yes and repairable", or Node a = findNodeInstance(…); a.isActive(). The trailing ; is optional; a bare comparison is accepted as the last line.

Unknown is false

Waiting for a node is normal

An Event_Flow is polled long before the actuality it watches exists. A node not found, a method called on null or an unresolved operand of && gives “unknown”, read as false. An evaluation error (syntax, unknown method, comparison with null) is logged and also counts as false: the flow is not followed, its otherwise flow is.

Task variables

Read from the running process

@variable[Function name] reads the output (or else input) variable of the task deduced from that function, in the current process instance first. $source.getOutputVariable("name") and getInputVariable("name") read the task the flow leaves. Values are typed from the declaration of the variable: number and slider give a float, checkbox and slide toggle a boolean ("true" or "yes"), any other type a string.

A Wait Condition is written on a Mediation function with the operation Wait Until, placed between two functions linked by plain Implies links; the task deduced from it copies the condition and its Wait Polling (s). It is evaluated the same way, every polling interval: $source is the wait, $target the task it leads to, so $target.createdFor() gives the objective that task was deduced for. A condition that cannot be evaluated yet keeps waiting; the wait stops without completing when the process ends, and is not observed in simulation (see waiting).

At deduction, the conditions of conditioned links are also replayed on every value their variables may take, to give each indicator of a branching solution an interval (see conditioned links).

07 · Methods

Every method of the language

The list is closed: a relation name called as a method (the former x.Rel("name")) raises an error that gives the arrow to write, any other unknown name raises “Method not defined”. The code editor completes them, with the relations and properties of the concept at hand.

MethodOnReturnsWhat it doesExample
Finding nodes
findNodeInstance("Concept", "name")—Node · nullThe instance of that concept with that name. Reference copies embedded in solutions are ignored; when several live instances share the name, an ACTIVE one is preferred.Barbecue: findNodeInstance("Kid", "Henri Martinez")
a -[Rel]-> (Type "name") · a <-[Rel]- ()NodeNode · list · nullRelation arrows (see section 03); a -[Rel]-> b tests an edge between two nodes.Orléans: $target <-[Fixed_Onto]- ("Loire water level - Orleans") · crisis roles: objective -[Prevents]-> (Risk)
createdFor()taskNode · list · nullThe objective(s) the deduction created the task for, read on its Created_By edge: the objective it satisfies for the task of the main function, the objectives concerned for the tasks of its prerequisites and follow-ups.Orléans: Node objective = $target.createdFor();
Status and type
isActive() · isFreeze()NodebooleanWhether the node has the ACTIVE or the FREEZE status.Orléans: zone.isActive()
active() · freeze()Node · list—Sets the status of the node, or of each node of the list. Rules only.Orléans: risk.active();
isInstanceOf("Concept")NodebooleanWhether the type of the node is the concept or inherits it.Healthcare: software.isInstanceOf("Good")
getId()NodetextIdentifier of the node.$source.getId()
Task variables (conditions)
@variable[Function name]—value · nullOutput, or else input, variable of the task deduced from the function; does not depend on where the planning placed the tasks.IMT Albi Crisis: @Confirmed gas leak[Confirm gas leak] == "Yes and non-repairable"
getOutputVariable("name") · getInputVariable("name")taskvalue · nullVariable of that task, read from the running process, or else from the properties saved on the task.$source.getOutputVariable("count") > 3
Geolocation
getGeoloc()NodegeolocationGeolocation of the node; error when the node has none.Barbecue: barbecue.getGeoloc()
getPosition()geolocationpointPoint, centre of the circle or centroid of the polygons.Orléans: sensor.getGeoloc().getPosition()
setPosition(point)geolocation—Moves the point or the centre of the circle. A null point keeps the current geometry. Rules only.Orléans: $source.getGeoloc().setPosition(sensor.getGeoloc().getPosition());
setRadius(metres)geolocation—Turns the geolocation into a circle of that radius (point, polygons and lines removed; style copied from the concept); place it with setPosition afterwards. Rules only.Orléans: $source.getGeoloc().setRadius(radius);
radiusgeolocationfloatRadius of the circle, in metres.Barbecue: highTemperature.getGeoloc().radius
isInside(areaNode)NodebooleanWhether the geolocation of the node lies inside the area of the other node.Barbecue: henri.isInside(swimmingPool)
Points
distanceTo(point)pointfloat · nullGreat-circle distance in metres; null when a point is unknown.Barbecue: henri.getGeoloc().getPosition().distanceTo(barbecue.getGeoloc().getPosition())
isNear(point, offset)pointbooleanTrue when both the latitude and the longitude differ by less than offset degrees. Not used by the packaged use cases: prefer distanceTo.a.isNear(b, 0.001)
getLatitude() · getLongitude()pointnumberCoordinates of the point, in degrees.p.getLatitude() > 43.9
setLatitude(v) · setLongitude(v)point—Changes a coordinate; expects the value of another point’s getLatitude() / getLongitude() (a literal is a float and is refused). Rules only.p.setLatitude(q.getLatitude());
Mathematics
Math.random(min, max)MathfloatRandom number between min and max.risk.probability = Math.random(0, 1);

“Rules only”: in a condition the call is allowed but nothing is saved. During the registration dry run these calls do nothing.

08 · Use-case examples

Scripts copied from the packaged use cases

Orléans Flood Crisis — a danger zone that follows the Loire

The potential Loire flooding is Generated_By the George-V bridge. Its rule reads the water level sensor fixed onto the bridge: from 1.50 m the zone is active, centred on the sensor, with a radius of 50 m per metre of water; below, it is frozen and shrunk.

Loire flooding –Generated_By→ George-V bridgeactivation condition
Node sensor = $target <-[Fixed_Onto]- ("Loire water level - Orleans");
if(sensor.currentValue >= 1.5) {
  Float radius = sensor.currentValue * 50;
  $source.active();
  $source.getGeoloc().setRadius(radius);
  $source.getGeoloc().setPosition(sensor.getGeoloc().getPosition());
} else {
  $source.freeze();
  $source.getGeoloc().setRadius(0);
  $source.getGeoloc().setPosition(null);
}

The risk George-V bridge flood risk is Generated_By that zone. From 2.50 m, the CEP rules of the sensor write its probability by tiers: 0.2 at 2.50 m, 0.5 at 3.50 m, 0.8 at 4.00 m and 1 at 4.50 m. Below 2.50 m no CEP threshold is ever crossed, so 2L sets the low tier: the risk is active at 0.05 as soon as the zone is. This rule replaces the default one, which would copy the probability of the zone onto the risk and overwrite the CEP tiers.

George-V bridge flood risk –Generated_By→ Loire floodingactivation condition
Node risk = $source;
Node zone = $target;
Node sensor = findNodeInstance("Sensor", "Loire water level - Orleans");
if(zone.isActive() && sensor.currentValue < 2.5 && risk.isFreeze()) {
  risk.probability = 0.05;
  risk.active();
  risk.getGeoloc().setPosition(sensor.getGeoloc().getPosition());
}
if(zone.isFreeze() && sensor.currentValue < 2.5 && risk.isActive()) {
  risk.probability = 0;
  risk.freeze();
  risk.getGeoloc().setPosition(null);
}

At 4.50 m the probability reaches 1: the Generated_By rule of the actuality Loire flood at George-V bridge activates it at the place of the risk and freezes the risk (if($target.probability >= 1), as in the default rule). The flood does not end as soon as the water goes down: the sensor threshold that raised it is released only once the level has stayed below 4.00 m for 6 hours (see Sensor interceptor).

Orléans Flood Crisis — waiting for the flood to recede before reopening

In the shared crisis roles, the Mediation function Wait until a bridge can be inspected sits between Close a bridge to traffic and Inspect a bridge after a flood, linked by plain Implies links. Its duration is a range of 6 to 24 h and it polls every 5 s. The deduced process closes the bridge, then the wait holds the inspection, and what follows it, until the condition is true; the tasks after it are planned in a window, from the shortest to the longest wait. The condition is generic: it finds the flood through the objective the inspection was deduced for, so the same function serves any bridge and any flood.

Wait until a bridge can be inspected (Mediation, Wait Until)Wait Condition
Node objective = $target.createdFor();
Node risk = objective -[Prevents]-> (Risk);
Node flood = risk <-[Generated_By]- (Actuality);
boolean cleared = flood == null || !flood.isActive();
boolean riskLow = risk == null || risk.probability < 0.8;
boolean reopen = cleared && riskLow;
reopen;

In the corrective procedure, Wait until the flood has receded sits the same way between Cut the utility networks crossing a bridge and Restore the utility networks crossing a bridge (6 to 24 h, every 5 s): the networks are restored once the flood the objective treats is no longer active.

Wait until the flood has receded (Mediation, Wait Until)Wait Condition
Node objective = $target.createdFor();
Node flood = objective -[Treats]-> (Actuality);
boolean cleared = flood == null || !flood.isActive();
cleared;

Barbecue — a burn risk that grows as Henri gets closer

The potential High Temperature is a 6 m zone around the barbecue, active while its thermal sensor reads 50 or more. The risk Henri risks getting burned is Generated_By that zone: its probability goes from 0 at the edge of the zone to 1 at 1.5 m from the barbecue, where the alert Henri burns takes over.

Henri risks getting burned –Generated_By→ High Temperatureactivation condition
Node riskBurns = $source;
Node highTemperature = $target;
Node objectiveRiskBurns = riskBurns <-[Prevents]- ("Prevent Henri risks getting burned");
Node actualityBurns = findNodeInstance("Alert", "Henri burns");
Node barbecue = findNodeInstance("Good", "Barbecue");
Node henri = findNodeInstance("Kid", "Henri Martinez");
if(henri != null && highTemperature.isActive() && actualityBurns.isFreeze() && henri.getGeoloc().getPosition().distanceTo(barbecue.getGeoloc().getPosition()) <= highTemperature.getGeoloc().radius) {
  Float distance = henri.getGeoloc().getPosition().distanceTo(barbecue.getGeoloc().getPosition());
  Float zoneRadius = highTemperature.getGeoloc().radius;
  if(distance > 1.5) {
    Float remaining = zoneRadius - distance;
    Float span = zoneRadius - 1.5;
    riskBurns.probability = remaining / span;
    riskBurns.getGeoloc().setPosition(henri.getGeoloc().getPosition());
    riskBurns.active();
    objectiveRiskBurns.active();
  }
} else {
  if(actualityBurns.isFreeze()) {
    riskBurns.probability = 0;
    riskBurns.freeze();
    objectiveRiskBurns.freeze();
  }
}

The drowning alert combines a distance and an area: Henri must be within 10 m of the pool and inside its polygon.

Henri drowns –Generated_By→ Henri is in danger of drowningextract
if(henri != null && henri.getGeoloc().getPosition().distanceTo(swimmingPool.getGeoloc().getPosition()) <= 10 && henri.isInside(swimmingPool)) {
  riskSubmersion.probability = 1;
  riskSubmersion.freeze();
  objectiveRiskSubmersion.freeze();
  actualitySubmersion.getGeoloc().setPosition(henri.getGeoloc().getPosition());
  actualitySubmersion.active();
  objectiveActualitySubmersion.active();
}

IMT Albi Healthcare — a susceptibility rule that walks the graph

A healthcare software is Is_Susceptible_To the potential Danger of Electrical Failure. The rule iterates over the risks that potential generates and activates each one, with its preventing objective, while the software lies inside the active zone and the risk is not yet certain.

Healthcare software –Is_Susceptible_To→ Danger of Electrical Failuresusceptibility condition
Node software = $source;
if(software.isInstanceOf("Good")) {
  Node potential = $target;
  List<Node> risks = potential <-[Generated_By]- ();
  for(Node risk: risks) {
    if(potential.isActive() && software.isInside(potential) && risk.probability < 1) {
      risk.active();
      if(risk <-[Prevents]- () != null) {
        risk <-[Prevents]- ().active();
      }
      risk.getGeoloc().setPosition(software.getGeoloc().getPosition());
    } else {
      risk.freeze();
      if(risk <-[Prevents]- () != null) {
        risk <-[Prevents]- ().freeze();
      }
      risk.getGeoloc().setPosition(null);
    }
  }
}

IMT Albi Crisis — conditioned links and a qualified corrective

The function Confirm gas leak implies two functions, each guarded by the answer the firefighter gives in the output variable Confirmed gas leak. The two conditions are exclusive: the deduced process keeps both branches and the engine follows one (see conditioned links).

Confirm gas leak –Implies→ Cut off the local gas valve · Cut off the school gas supplyCondition Evaluation
@Confirmed gas leak[Confirm gas leak] == "Yes and repairable"
@Confirmed gas leak[Confirm gas leak] == "Yes and non-repairable"

When the deduction selects a corrective for a risk found by the ML detection, the planner writes the condition of the Event_Flow attached to the nominal sub-task. The actuality name alone is not enough, since the same Power outage can be generated by several risks: the condition also requires the actuality to be linked to the validated risk, in either direction, since the ML detection writes the Generated_By edge from the risk to the actuality and a modelled use case usually the other way (corrective procedures walkthrough).

Nominal SubTask –Event_Flow→ corrective sub-processCondition Evaluation (generated)
Node triggerActuality = findNodeInstance("Actuality", "Power outage");
boolean generated = triggerActuality <-[Generated_By]- ("Power outages") != null || triggerActuality -[Generated_By]-> ("Power outages") != null;
boolean triggered = triggerActuality.isActive() && generated;
triggered;

An implementation risk attached to a task gets an Exception_Flow instead, whose generated condition only watches the actuality (recovery procedures walkthrough):

Blood test Request –Exception_Flow→ recovery sub-processCondition Evaluation (generated)
findNodeInstance("Actuality", "Healthcare software unavailability for Blood Test Request Function").isActive()
09 · Watch points

What to keep in mind

Names

Strings are exact

findNodeInstance and Relation("name") match the name exactly (spaces and case included). A renamed node silently makes the rule see null.

Guards

Test null first

In a rule, calling a method on null or comparing null with < is an error and the rule is skipped for the wave. Start the condition with x != null && …, as the Barbecue rules do with henri.

Stability

Write rules that settle

Change a status only when it differs (if($source.isFreeze()) $source.active();). Two rules that keep undoing each other make the wave stop on an oscillation.

Triggers

Only ACTIVE starts a wave

A node frozen by another mechanism (a CEP rule, the user) does not run the rules that read it until an ACTIVE node they watch changes again.

Numbers

Equality between numbers

== compares values of the same kind: probabilities, metrics and literals are floats and compare well, but coordinates are doubles. Compare coordinates with <= / >=.

Parentheses

No grouping in expressions

(a || b) && c is a syntax error. Name each part: boolean cleared = flood == null || !flood.isActive();, then combine the variables.

Quotes

Quote text values

@x[F] == Yes is a syntax error: the condition is never true. Write "Yes", exactly as the value of the variable.

10 · Sources

Implementation

Référence / Modèles & DSL

Le langage 2L

2L est le petit langage écrit sur les arêtes du modèle collaboratif. Il dit quand un problème devient actif, où se trouve sa zone et quelle est sa probabilité, et il garde les liens et les flux d’un processus déduit : quelle tâche s’exécute après une autre, quand démarre un correctif ou une reprise. Cette page présente où 2L est utilisé, sa syntaxe, l’exécution des règles et des conditions et chaque méthode, chacune avec un exemple tiré d’un cas d’usage.

01 · Où 2L est utilisé

Deux sortes de code : règles et conditions

Toute propriété de relation de type éditeur de code marquée RIO_2L dans le métamodèle collaboratif contient du 2L. Une règle agit sur le modèle (statut, probabilité, position, zone) ; une condition répond vrai ou faux et ne modifie rien qui soit conservé.

ArêtePropriétéSorteÉvaluée$source / $target
Règles — exécutées par le gestionnaire 2L sur le graphe de connaissances
Generated_Byactivation conditionrègleDans une vague de propagation, quand un nœud lu par la règle devient ou reste ACTIVESource et cible de l’arête, par exemple le problème généré et ce qui le génère (capteur, actif, potentiel, risque)
Is_Susceptible_Tosusceptibility conditionrègleIdemL’actif ou le rôle exposé / la potentialité à laquelle il est exposé
Impactsimpacts conditionrègleIdemLe problème / l’actif, le rôle ou la ressource touché
Generatesgeneration conditionrègleIdemSource et cible de l’arête (aucun cas d’usage livré ne la remplit)
Conditions — propriété « Condition Evaluation », évaluée par le moteur de workflow PRIO
Implies · Supports · NeedsCondition EvaluationconditionJamais sur le lien lui-même : la déduction la recopie sur les Sequence_Flow qui entrent dans la tâche gardée, lue une fois (voir liens conditionnés)—
Fonction Mediation « Wait Until »Wait ConditionconditionSur la tâche déduite de la fonction : au début de l’attente, puis toutes les Wait Polling (s) (5 par défaut) jusqu’à ce qu’elle soit vraie ; seule sa branche attendLa tâche d’attente / la tâche à laquelle elle mène
Sequence_FlowCondition EvaluationconditionQuand le processus quitte le nœud source du fluxLe nœud quitté / le nœud suivant du flux
Event_FlowCondition EvaluationconditionAu démarrage de la sous-tâche nominale, puis toutes les 5 s tant qu’elle s’exécute ; se déclenche au plus une foisLa sous-tâche nominale / le sous-processus correctif
Exception_FlowCondition EvaluationconditionAu démarrage de la tâche, puis toutes les 5 s tant qu’une tâche humaine s’exécuteLa tâche / son sous-processus de reprise
$source et $target suivent l’arête, pas un rôle

Les deux variables désignent la source et la cible réelles de l’arête. Des règles Generated_By par défaut existent dans les deux sens (actualité → potentialité et l’inverse) : avant d’écrire une règle, vérifier sur le diagramme quel nœud est la source.

02 · Syntaxe

Un petit sous-ensemble de Java

La grammaire est un Java réduit : déclarations, if / else, for sur une liste, appels de méthodes, lecture et écriture de propriétés. Il n’y a ni return, ni while, ni déclaration de classe ou de méthode.

Instructions

Ce qu’une ligne peut être

  • une déclaration : Node sensor = …;, Float radius = …;, List<Node> risks = …;, boolean ok = …;
  • un appel de méthode : $source.active();
  • une écriture de propriété : risk.probability = 0.05;
  • if (…) { … } else { … }, imbriqués à volonté
  • for (Node risk : risks) { … }
  • des commentaires // et /* … */
Types

Déclarés, à peine vérifiés

Node, boolean, int, float, double et tout nom comme Float ou String sont acceptés. Seul List<…> compte : une variable liste contient toujours une liste (un nœud seul y est enveloppé, rien donne une liste vide), et une variable simple qui reçoit une liste garde son premier élément.

Littéraux

Les nombres sont des Float

Entiers et décimaux (1, 0.05) deviennent des flottants 32 bits : $target.probability == 1 fonctionne donc sur une probabilité lue comme flottant. Les chaînes sont entre guillemets doubles ("Yes and repairable") ; true, false et null sont disponibles.

OpérateurOpérandesRésultat
== · !=tout ; les propriétés sont d’abord converties (voir Valeurs)égalité de valeur ; null == null est vrai, x == null teste une absence
< · > · <= · >=nombresbooléen ; un opérande null est une erreur dans une règle
+deux nombres, ou deux chaînessomme, ou concaténation
- · * · /nombresflottant ; la division par zéro est une erreur
&&booléensfaux dès que la partie gauche est fausse : la partie droite est quand même lue (pour savoir quels nœuds la règle surveille) mais ses erreurs sont ignorées, donc henri != null && henri.getGeoloc()… est sûr
||booléensvrai dès que la partie gauche est vraie, même tolérance
! · - unairebooléen · nombrenégation
@variable[Nom de la fonction]—valeur d’une variable de tâche à l’exécution (voir Conditions)

Non interprétés bien que l’analyseur les accepte : %, ++ / --, le ternaire ?:, les conversions de type et instanceof (utiliser isInstanceOf("Concept")). Les affectations composées (+=…) se comportent comme un simple =. Une variable locale ne peut pas être réaffectée après sa déclaration : en déclarer une nouvelle. Les expressions n’ont pas de parenthèses : (a || b) && c ne s’analyse pas ; écrire plutôt des variables booléennes intermédiaires (boolean cleared = …; boolean reopen = cleared && riskLow;).

03 · Flèches de relation

Suivre les arêtes, écrit comme en Cypher

Une flèche va d’un nœud à ses voisins par les arêtes d’une relation, dans le sens où l’arête est enregistrée dans le modèle. L’ancienne forme d’appel x.Relation("nom") ne fait plus partie du langage : l’interpréteur la refuse avec une erreur qui donne la flèche à écrire.

FormeDonne
a -[Rel]-> (Type "nom")les nœuds au bout des arêtes Rel qui partent de a
a <-[Rel]- (Type "nom")les nœuds au départ des arêtes Rel qui arrivent sur a
(Type) · ("nom") · ()le motif filtre par concept (les concepts qui en héritent conviennent aussi) et par nom exact, tous deux facultatifs
a -[Rel]-> b · a <-[Rel]- bavec une expression à la place du motif : vrai quand une telle arête relie a au nœud b
a <-[Prevents]- ().active();un appel de méthode ou une lecture de propriété peut suivre le motif, et une instruction peut commencer par une flèche

Une traversée donne null quand rien ne correspond, le nœud quand un seul correspond, une liste sinon. Les copies de référence embarquées dans les solutions sont écartées, comme dans findNodeInstance. Une relation ou un concept inconnu est une erreur.

Tirées des cas d’usage livrésflèches
Node sensor = $target <-[Fixed_Onto]- ("Loire water level - Orleans");   // Orléans : le capteur fixé sur le pont
if($target <-[Fixed_Onto]- ("Barbecue thermal sensor").currentValue >= 50) { … }   // Barbecue
Node objectiveRiskBurns = riskBurns <-[Prevents]- ("Prevent Henri risks getting burned");
List<Node> risks = potential <-[Generated_By]- ();   // Healthcare : les risques générés par le potentiel
risk <-[Prevents]- ().active();
Node risk = objective -[Prevents]-> (Risk);            // rôles de crise : le risque que l’objectif prévient
Node flood = risk <-[Generated_By]- (Actuality);
Lire la flèche comme l’arête

Un objectif prévient un risque par une arête objectif –Prevents→ risque : depuis l’objectif on écrit objective -[Prevents]-> (Risk), depuis le risque risk <-[Prevents]- (). Quand le sens d’une arête dépend de qui l’a écrite, tester les deux flèches (voir l’exemple d’Event_Flow plus bas).

04 · Valeurs

Ce que donne une expression

ExpressionValeur
$source, $target, findNodeInstance(…)un nœud du graphe de connaissances, ou null
a -[Rel]-> (…), a <-[Rel]- (…)un nœud, une liste ou null ; a -[Rel]-> b donne un booléen (voir Flèches de relation)
noeud.proprietela propriété de ce nom, convertie quand elle est comparée, calculée ou affectée : une métrique (probability, currentValue…) donne sa valeur précise en flottant, une propriété numérique un flottant, toute autre propriété son texte ; null si le nœud n’a pas cette propriété
noeud.statusla liste des statuts du nœud (préférer isActive() / isFreeze())
noeud.getGeoloc()la géolocalisation du nœud (point, cercle, polygones ou lignes)
geoloc.getPosition()un point : le point lui-même, le centre du cercle ou le centroïde des polygones
geoloc.radiusle rayon du cercle, en mètres
Mathla seule variable prédéfinie, pour Math.random(min, max)

Seules les propriétés dont le nom est un identifiant valide se lisent avec le point (currentValue, probability, name). Écrire une propriété (risk.probability = remaining / span;) met à jour la valeur précise d’une métrique ou range le texte de la valeur ; une propriété que le nœud n’a pas n’est pas créée.

05 · Règles

Exécution des règles : vagues de propagation

Les règles d’un espace de connaissances sont enregistrées à l’écriture de leur arête (intercepteur Code2L) et réexécutées chaque fois que la situation qu’elles lisent change.

1 · Enregistrement

Un passage à blanc trouve ce que la règle surveille

La règle est interprétée une fois en lecture seule : chaque nœud lu dans une condition de if ou dans la liste d’un for est abonné. active(), freeze(), les positions et les écritures de propriétés sont ignorés pendant ce passage. Une règle dont tous les nœuds ne sont pas encore connus est réanalysée plus tard.

2 · Déclenchement

Un nœud ACTIVE lance une vague

Quand un nœud est ajouté ou mis à jour avec le statut ACTIVE (valeur de capteur, problème activé…), les règles abonnées à ce nœud lancent une vague. Une mise à jour en FREEZE seule ne lance rien. Les vagues d’un même espace de connaissances s’exécutent l’une après l’autre.

3 · Point fixe

Enchaînées en mémoire, enregistrées une fois

Les règles s’exécutent en mémoire, puis celles de chaque nœud qu’elles ont modifié, et ainsi de suite jusqu’à ce que plus rien ne change (25 passes au plus ; un nœud qui revient à un état antérieur arrête la vague). Une règle en erreur est sautée sans annuler les autres. Les nœuds modifiés sont ensuite publiés ensemble, et les objectifs gelés qui traitent, préviennent ou permettent un problème devenu actif sont activés dans la même publication.

Une vagueLLManager.runFixpoint
travail = { nœud déclencheur }              # un nœud ACTIVE ajouté ou mis à jour
tant que travail non vide et passe < 25 :
  pour nœud dans travail :
    pour règle qui surveille nœud :
      exécuter la règle sur les copies en mémoire   # findNodeInstance voit l’état calculé par les autres règles
      suivant += nœuds réellement modifiés           # même état qu’avant : pas un changement
  arrêt si un nœud revient à un état antérieur
  travail = suivant
publier les nœuds modifiés + objectifs des problèmes devenus ACTIVE
06 · Conditions

Évaluation des conditions

Une Condition Evaluation est une expression booléenne, éventuellement précédée de déclarations. Elle est évaluée par le moteur PRIO au besoin, jamais enregistrée comme règle, et n’enregistre jamais rien.

Forme

Des instructions, puis une expression

La dernière instruction donne le résultat : @Confirmed gas leak[Confirm gas leak] == "Yes and repairable", ou Node a = findNodeInstance(…); a.isActive(). Le ; final est facultatif ; une comparaison nue est acceptée en dernière ligne.

Inconnu = faux

Attendre un nœud est normal

Un Event_Flow est interrogé bien avant que l’actualité qu’il surveille existe. Un nœud introuvable, une méthode appelée sur null ou un opérande non résolu de && donnent « inconnu », lu comme faux. Une erreur d’évaluation (syntaxe, méthode inconnue, comparaison avec null) est journalisée et compte aussi comme faux : le flux n’est pas suivi, son flux otherwise l’est.

Variables de tâche

Lues dans le processus en cours

@variable[Nom de la fonction] lit la variable de sortie (ou à défaut d’entrée) de la tâche déduite de cette fonction, dans l’instance de processus en cours d’abord. $source.getOutputVariable("nom") et getInputVariable("nom") lisent la tâche que le flux quitte. Les valeurs sont typées par la déclaration de la variable : number et slider donnent un flottant, checkbox et slide toggle un booléen ("true" ou "yes"), tout autre type une chaîne.

Une Wait Condition s’écrit sur une fonction Mediation d’opération Wait Until, placée entre deux fonctions reliées par de simples liens Implies ; la tâche déduite de cette fonction recopie la condition et son Wait Polling (s). Elle est évaluée de la même façon, à chaque intervalle de scrutation : $source est l’attente, $target la tâche à laquelle elle mène, donc $target.createdFor() donne l’objectif pour lequel cette tâche a été déduite. Une condition pas encore évaluable continue d’attendre ; l’attente s’arrête sans se terminer quand le processus finit, et n’est pas observée en simulation (voir attendre).

À la déduction, les conditions des liens conditionnés sont aussi rejouées sur toutes les valeurs que peuvent prendre leurs variables, pour donner à chaque indicateur d’une solution à branches un intervalle (voir liens conditionnés).

07 · Méthodes

Toutes les méthodes du langage

La liste est fermée : un nom de relation appelé comme une méthode (l’ancienne forme x.Rel("nom")) lève une erreur qui donne la flèche à écrire, tout autre nom inconnu lève « Method not defined ». L’éditeur de code les complète, avec les relations et propriétés du concept concerné.

MéthodeSurRenvoieCe qu’elle faitExemple
Trouver des nœuds
findNodeInstance("Concept", "nom")—Node · nullL’instance de ce concept portant ce nom. Les copies de référence embarquées dans les solutions sont ignorées ; si plusieurs instances vivantes partagent le nom, une instance ACTIVE est préférée.Barbecue : findNodeInstance("Kid", "Henri Martinez")
a -[Rel]-> (Type "nom") · a <-[Rel]- ()NodeNode · liste · nullFlèches de relation (voir la section 03) ; a -[Rel]-> b teste une arête entre deux nœuds.Orléans : $target <-[Fixed_Onto]- ("Loire water level - Orleans") · rôles de crise : objective -[Prevents]-> (Risk)
createdFor()tâcheNode · liste · nullLe ou les objectifs pour lesquels la déduction a créé la tâche, lus sur son arête Created_By : l’objectif satisfait pour la tâche de la fonction principale, les objectifs concernés pour les tâches de ses prérequis et de ses suites.Orléans : Node objective = $target.createdFor();
Statut et type
isActive() · isFreeze()NodebooléenLe nœud a-t-il le statut ACTIVE ou FREEZE.Orléans : zone.isActive()
active() · freeze()Node · liste—Fixe le statut du nœud, ou de chaque nœud de la liste. Règles seulement.Orléans : risk.active();
isInstanceOf("Concept")NodebooléenLe type du nœud est-il ce concept ou en hérite-t-il.Healthcare : software.isInstanceOf("Good")
getId()NodetexteIdentifiant du nœud.$source.getId()
Variables de tâche (conditions)
@variable[Nom de la fonction]—valeur · nullVariable de sortie, ou à défaut d’entrée, de la tâche déduite de la fonction ; ne dépend pas de l’endroit où la planification a placé les tâches.IMT Albi Crisis : @Confirmed gas leak[Confirm gas leak] == "Yes and non-repairable"
getOutputVariable("nom") · getInputVariable("nom")tâchevaleur · nullVariable de cette tâche, lue dans le processus en cours, ou à défaut dans les propriétés enregistrées sur la tâche.$source.getOutputVariable("count") > 3
Géolocalisation
getGeoloc()NodegéolocalisationGéolocalisation du nœud ; erreur si le nœud n’en a pas.Barbecue : barbecue.getGeoloc()
getPosition()géolocalisationpointPoint, centre du cercle ou centroïde des polygones.Orléans : sensor.getGeoloc().getPosition()
setPosition(point)géolocalisation—Déplace le point ou le centre du cercle. Un point null garde la géométrie actuelle. Règles seulement.Orléans : $source.getGeoloc().setPosition(sensor.getGeoloc().getPosition());
setRadius(mètres)géolocalisation—Transforme la géolocalisation en cercle de ce rayon (point, polygones et lignes retirés ; style recopié du concept) ; la placer ensuite avec setPosition. Règles seulement.Orléans : $source.getGeoloc().setRadius(radius);
radiusgéolocalisationflottantRayon du cercle, en mètres.Barbecue : highTemperature.getGeoloc().radius
isInside(noeudZone)NodebooléenLa géolocalisation du nœud est-elle dans la zone de l’autre nœud.Barbecue : henri.isInside(swimmingPool)
Points
distanceTo(point)pointflottant · nullDistance orthodromique en mètres ; null si un point est inconnu.Barbecue : henri.getGeoloc().getPosition().distanceTo(barbecue.getGeoloc().getPosition())
isNear(point, écart)pointbooléenVrai quand la latitude et la longitude diffèrent toutes deux de moins de écart degrés. Non utilisée par les cas d’usage livrés : préférer distanceTo.a.isNear(b, 0.001)
getLatitude() · getLongitude()pointnombreCoordonnées du point, en degrés.p.getLatitude() > 43.9
setLatitude(v) · setLongitude(v)point—Change une coordonnée ; attend la valeur de getLatitude() / getLongitude() d’un autre point (un littéral est un flottant et il est refusé). Règles seulement.p.setLatitude(q.getLatitude());
Mathématiques
Math.random(min, max)MathflottantNombre aléatoire entre min et max.risk.probability = Math.random(0, 1);

« Règles seulement » : dans une condition l’appel est permis mais rien n’est enregistré. Pendant le passage à blanc de l’enregistrement, ces appels ne font rien.

08 · Exemples des cas d’usage

Scripts recopiés des cas d’usage livrés

Orléans Flood Crisis — une zone de danger qui suit la Loire

Le potentiel Loire flooding est Generated_By le pont George-V. Sa règle lit le capteur de niveau d’eau fixé sur le pont : à partir de 1,50 m la zone est active, centrée sur le capteur, avec un rayon de 50 m par mètre d’eau ; en dessous, elle est gelée et réduite.

Loire flooding –Generated_By→ George-V bridgeactivation condition
Node sensor = $target <-[Fixed_Onto]- ("Loire water level - Orleans");
if(sensor.currentValue >= 1.5) {
  Float radius = sensor.currentValue * 50;
  $source.active();
  $source.getGeoloc().setRadius(radius);
  $source.getGeoloc().setPosition(sensor.getGeoloc().getPosition());
} else {
  $source.freeze();
  $source.getGeoloc().setRadius(0);
  $source.getGeoloc().setPosition(null);
}

Le risque George-V bridge flood risk est Generated_By cette zone. À partir de 2,50 m, les règles CEP du capteur écrivent sa probabilité par paliers : 0,2 à 2,50 m, 0,5 à 3,50 m, 0,8 à 4,00 m et 1 à 4,50 m. Sous 2,50 m aucun seuil CEP n’est jamais franchi : 2L fixe donc le palier bas, le risque est actif à 0,05 dès que la zone l’est. Cette règle remplace la règle par défaut, qui recopierait la probabilité de la zone sur le risque et écraserait les paliers CEP.

George-V bridge flood risk –Generated_By→ Loire floodingactivation condition
Node risk = $source;
Node zone = $target;
Node sensor = findNodeInstance("Sensor", "Loire water level - Orleans");
if(zone.isActive() && sensor.currentValue < 2.5 && risk.isFreeze()) {
  risk.probability = 0.05;
  risk.active();
  risk.getGeoloc().setPosition(sensor.getGeoloc().getPosition());
}
if(zone.isFreeze() && sensor.currentValue < 2.5 && risk.isActive()) {
  risk.probability = 0;
  risk.freeze();
  risk.getGeoloc().setPosition(null);
}

À 4,50 m la probabilité atteint 1 : la règle Generated_By de l’actualité Loire flood at George-V bridge l’active à l’endroit du risque et gèle le risque (if($target.probability >= 1), comme la règle par défaut). La crue ne se termine pas dès que l’eau baisse : le seuil du capteur qui l’a levée n’est relâché qu’une fois le niveau resté 6 heures sous 4,00 m (voir l’intercepteur Sensor).

Orléans Flood Crisis — attendre la fin de la crue avant de rouvrir

Dans les rôles de crise partagés, la fonction Mediation Wait until a bridge can be inspected se place entre Close a bridge to traffic et Inspect a bridge after a flood, reliées par de simples liens Implies. Sa durée est un intervalle de 6 à 24 h et elle scrute toutes les 5 s. Le processus déduit ferme le pont, puis l’attente retient l’inspection, et ce qui la suit, jusqu’à ce que la condition soit vraie ; les tâches qui la suivent sont planifiées dans une fenêtre, de l’attente la plus courte à la plus longue. La condition est générique : elle retrouve la crue par l’objectif pour lequel l’inspection a été déduite, la même fonction sert donc pour n’importe quel pont et n’importe quelle crue.

Wait until a bridge can be inspected (Mediation, Wait Until)Wait Condition
Node objective = $target.createdFor();
Node risk = objective -[Prevents]-> (Risk);
Node flood = risk <-[Generated_By]- (Actuality);
boolean cleared = flood == null || !flood.isActive();
boolean riskLow = risk == null || risk.probability < 0.8;
boolean reopen = cleared && riskLow;
reopen;

Dans la procédure corrective, Wait until the flood has receded se place de la même façon entre Cut the utility networks crossing a bridge et Restore the utility networks crossing a bridge (6 à 24 h, toutes les 5 s) : les réseaux sont rétablis une fois que la crue traitée par l’objectif n’est plus active.

Wait until the flood has receded (Mediation, Wait Until)Wait Condition
Node objective = $target.createdFor();
Node flood = objective -[Treats]-> (Actuality);
boolean cleared = flood == null || !flood.isActive();
cleared;

Barbecue — un risque de brûlure qui grandit quand Henri s’approche

Le potentiel High Temperature est une zone de 6 m autour du barbecue, active tant que son capteur thermique indique 50 ou plus. Le risque Henri risks getting burned est Generated_By cette zone : sa probabilité va de 0 au bord de la zone à 1 à 1,5 m du barbecue, où l’alerte Henri burns prend le relais.

Henri risks getting burned –Generated_By→ High Temperatureactivation condition
Node riskBurns = $source;
Node highTemperature = $target;
Node objectiveRiskBurns = riskBurns <-[Prevents]- ("Prevent Henri risks getting burned");
Node actualityBurns = findNodeInstance("Alert", "Henri burns");
Node barbecue = findNodeInstance("Good", "Barbecue");
Node henri = findNodeInstance("Kid", "Henri Martinez");
if(henri != null && highTemperature.isActive() && actualityBurns.isFreeze() && henri.getGeoloc().getPosition().distanceTo(barbecue.getGeoloc().getPosition()) <= highTemperature.getGeoloc().radius) {
  Float distance = henri.getGeoloc().getPosition().distanceTo(barbecue.getGeoloc().getPosition());
  Float zoneRadius = highTemperature.getGeoloc().radius;
  if(distance > 1.5) {
    Float remaining = zoneRadius - distance;
    Float span = zoneRadius - 1.5;
    riskBurns.probability = remaining / span;
    riskBurns.getGeoloc().setPosition(henri.getGeoloc().getPosition());
    riskBurns.active();
    objectiveRiskBurns.active();
  }
} else {
  if(actualityBurns.isFreeze()) {
    riskBurns.probability = 0;
    riskBurns.freeze();
    objectiveRiskBurns.freeze();
  }
}

L’alerte de noyade combine une distance et une zone : Henri doit être à moins de 10 m de la piscine et dans son polygone.

Henri drowns –Generated_By→ Henri is in danger of drowningextrait
if(henri != null && henri.getGeoloc().getPosition().distanceTo(swimmingPool.getGeoloc().getPosition()) <= 10 && henri.isInside(swimmingPool)) {
  riskSubmersion.probability = 1;
  riskSubmersion.freeze();
  objectiveRiskSubmersion.freeze();
  actualitySubmersion.getGeoloc().setPosition(henri.getGeoloc().getPosition());
  actualitySubmersion.active();
  objectiveActualitySubmersion.active();
}

IMT Albi Healthcare — une règle de susceptibilité qui parcourt le graphe

Un logiciel de santé est Is_Susceptible_To le potentiel Danger of Electrical Failure. La règle parcourt les risques générés par ce potentiel et active chacun d’eux, avec son objectif de prévention, tant que le logiciel est dans la zone active et que le risque n’est pas encore certain.

Healthcare software –Is_Susceptible_To→ Danger of Electrical Failuresusceptibility condition
Node software = $source;
if(software.isInstanceOf("Good")) {
  Node potential = $target;
  List<Node> risks = potential <-[Generated_By]- ();
  for(Node risk: risks) {
    if(potential.isActive() && software.isInside(potential) && risk.probability < 1) {
      risk.active();
      if(risk <-[Prevents]- () != null) {
        risk <-[Prevents]- ().active();
      }
      risk.getGeoloc().setPosition(software.getGeoloc().getPosition());
    } else {
      risk.freeze();
      if(risk <-[Prevents]- () != null) {
        risk <-[Prevents]- ().freeze();
      }
      risk.getGeoloc().setPosition(null);
    }
  }
}

IMT Albi Crisis — liens conditionnés et correctif qualifié

La fonction Confirm gas leak implique deux fonctions, chacune gardée par la réponse que le pompier donne dans la variable de sortie Confirmed gas leak. Les deux conditions sont exclusives : le processus déduit garde les deux branches et le moteur en suit une (voir liens conditionnés).

Confirm gas leak –Implies→ Cut off the local gas valve · Cut off the school gas supplyCondition Evaluation
@Confirmed gas leak[Confirm gas leak] == "Yes and repairable"
@Confirmed gas leak[Confirm gas leak] == "Yes and non-repairable"

Quand la déduction retient un correctif pour un risque trouvé par la détection ML, le planificateur écrit la condition de l’Event_Flow attaché à la sous-tâche nominale. Le nom de l’actualité ne suffit pas, puisque la même Power outage peut être générée par plusieurs risques : la condition exige aussi que l’actualité soit liée au risque validé, dans un sens ou dans l’autre, car la détection ML écrit l’arête Generated_By du risque vers l’actualité et un cas d’usage modélisé en général dans l’autre sens (parcours des procédures correctives).

Nominal SubTask –Event_Flow→ sous-processus correctifCondition Evaluation (générée)
Node triggerActuality = findNodeInstance("Actuality", "Power outage");
boolean generated = triggerActuality <-[Generated_By]- ("Power outages") != null || triggerActuality -[Generated_By]-> ("Power outages") != null;
boolean triggered = triggerActuality.isActive() && generated;
triggered;

Un risque de mise en œuvre attaché à une tâche reçoit plutôt un Exception_Flow, dont la condition générée ne surveille que l’actualité (parcours des procédures de reprise) :

Blood test Request –Exception_Flow→ sous-processus de repriseCondition Evaluation (générée)
findNodeInstance("Actuality", "Healthcare software unavailability for Blood Test Request Function").isActive()
09 · Points de vigilance

À garder en tête

Noms

Les chaînes sont exactes

findNodeInstance et Relation("nom") comparent le nom exactement (espaces et casse compris). Un nœud renommé fait voir null à la règle, sans message.

Gardes

Tester null d’abord

Dans une règle, appeler une méthode sur null ou comparer null avec < est une erreur et la règle est sautée pour la vague. Commencer la condition par x != null && …, comme les règles du Barbecue avec henri.

Stabilité

Écrire des règles qui se stabilisent

Ne changer un statut que s’il diffère (if($source.isFreeze()) $source.active();). Deux règles qui se défont l’une l’autre arrêtent la vague sur une oscillation.

Déclencheurs

Seul ACTIVE lance une vague

Un nœud gelé par un autre mécanisme (règle CEP, utilisateur) ne réexécute pas les règles qui le lisent tant qu’un nœud ACTIVE qu’elles surveillent ne change pas à nouveau.

Nombres

Égalité entre nombres

== compare des valeurs de même nature : probabilités, métriques et littéraux sont des flottants et se comparent bien, mais les coordonnées sont des doubles. Comparer les coordonnées avec <= / >=.

Parenthèses

Pas de regroupement dans les expressions

(a || b) && c est une erreur de syntaxe. Nommer chaque partie : boolean cleared = flood == null || !flood.isActive();, puis combiner les variables.

Guillemets

Mettre les textes entre guillemets

@x[F] == Yes est une erreur de syntaxe : la condition n’est jamais vraie. Écrire "Yes", exactement comme la valeur de la variable.

10 · Sources

Implémentation