The Gate Condition Is Written on the Diagram - Using BPMN as a Governance Spine
The gateway in this process carries this name: “ConfDecay over_trust_gap > 0.2 OR final ≥ 4.5 OR runtime alert?” The condition is written on the diagram as a string, and that is the whole point of this arrangement. The tool that diagnoses AI workflows was drawn as a BPMN process, with the coded agent as one node inside it. How using a process engine as a wrapper differs from using it as the spine of judgment, and the three problems that actually blocked the run.
Part 3 ended with a design where the human gate is fired by arithmetic rather than by an operator’s judgment. The remaining question is where to hang that gate.
Drawing the diagnosis as a process
Counting elements in the process definition file gives 1 start event, 2 end events, 3 exclusive gateways, 2 parallel gateways, 9 service tasks, and 1 user task: 18 flow objects, joined by 20 flows.

Read it left to right. A workflow diagram arrives, a parser task using document understanding receives it, and the first exclusive gateway decides whether there is at least one AI intervention node. If not, it ends without diagnosis.
If so, a parallel gateway fans out three ways: general failure, security, handoff. Each axis is drawn as its own service task and they rejoin at a second parallel gateway. Incident retrieval and mitigation ordering follow, and the second exclusive gateway splits on human review.

In the deployed run, one coded agent takes that diagnosis segment. The entry point is run() in coded_agent_wrapper.py, and inside it the order is:
| Stage | What it does | Character |
|---|---|---|
| Parse | Read the node inventory table into a node list | Deterministic |
| Select candidates | Score only nodes the ontology has cells for | Deterministic |
| Attach evidence | Retrieve precedents per node from the incident corpus | Retrieval-based |
| Handoff metrics | Compute IPS, confidence decay, and judge per node pair | Parallel |
| Aggregate and gate | Weighted sum, color band, gate condition evaluation | Deterministic |
The whole segment takes roughly 33 seconds. Three values come back: the per-node diagnosis list, the maximum score, and whether human review is required.
Of those three the process actually reads only the last. The gateway sees one boolean. The decision logic lives inside the agent and the process consumes the result, so a change in thresholds leaves the process definition untouched.
The condition is written on the diagram
The second gateway is named:
ConfDecay over_trust_gap > 0.2 OR final ≥ 4.5 OR runtime alert?
That is the core of this arrangement. What opens the gate is written on the process picture as a string. A regulatory reviewer does not have to open the repository or read Python to confirm that an over-trust gap above 0.2 escalates to a human.
The same condition exists in code. evaluate_hitl() checks the final score, the over-trust gap, the intent preservation score, and the judge score in order, accumulating the reasons it tripped as strings. The gateway’s name is the human-readable edition of that function. The two must not diverge, so the thresholds live in one place, held on a contract object that every execution path reads.
How far the input is actually wired
The parser task at the front of the process uses document understanding. What the coded agent parses, though, is a markdown node inventory table: node id, function, and how AI intervenes, as columns.
The repository holds a BPMN XML parser, a Mermaid parser, and a module that reads an image with a multimodal model and converts it to Mermaid, which then reuses the Mermaid parser. All three work, none is wired into the coded agent on the UiPath path, and the engine still carries a note that raw BPMN XML is not auto-converted yet.
The reason to open the input wide is practical. At the moment a pre-deployment check is needed, the workflow is rarely a standard-format file. It is a photograph of a design-session whiteboard, a cluster of shapes on a slide, or a diagram inside a document. Narrow the input to BPMN files and redrawing the workflow becomes a prerequisite, and once that attaches, the tool is a project again.
Stated plainly, though: the design for opening it wide exists and the wiring is half done.
Wrapper versus spine
There are two ways to put an agent on top of a process engine. They look similar; what differs is where the judgment lives.
| Dimension | Used as a wrapper | Used as a spine |
|---|---|---|
| Gate location | Conditional inside agent code | Gateway in the process definition |
| State ownership | The agent process | The process engine |
| Human involvement | The agent sends a notification | The process waits at a human task |
| Audit record | Log files | The execution history itself |
| Changing rules | Edit code and redeploy | Edit the process definition |
| Non-developer readability | Requires reading code | Readable as a diagram |
The last two rows were decisive. Proving that human review was placed on the auto-approval node by screenshotting a conditional in a code repository carries different weight than pointing at a gateway in a process diagram.
State ownership is the same story. A human review task can wait for days. If the agent process holds the state, restarts and deployments and outages all become risks, and with several cases pending you need separate machinery to track each. Hand it to the engine’s durable execution and pending instances are managed as a list, with who approved when written into the execution history.
Part 3 named permanent retention of the reasoning trace as the must-fix mitigation for the auto-approval node, and this arrangement is why that retention can ride on the execution history rather than becoming a separate feature. Tracing why an auto-approved case was approved needs the diagnosis at that moment, the gate decision, and the approver, and all three are in the history.
---
config:
look: handDrawn
theme: neutral
---
flowchart TD
subgraph W["Wrapper arrangement"]
W1["Process engine"] --> W2["Agent<br/>judgment · gate · notify"]
W2 --> W3["Log file"]
end
subgraph S["Spine arrangement"]
S1["Process definition<br/>gateways · human task"] --> S2["Agent<br/>scoring only"]
S2 --> S1
S1 --> S3["Execution history = audit record"]
endThis arrangement is not free
The price of the spine is flexibility. Writing the gate condition into the process definition means editing and redeploying the process to change it. What would be one configuration value with a code conditional becomes a diagram edit.
What the agent can do narrows too. A design where the agent decides mid-diagnosis that “this should go to a human” and alters the flow does not work here. The agent returns values; branching happens outside.
So the choice depends on use. For an agent doing exploratory work, the wrapper is right. When the output serves as regulatory material and the existence of the gate has to be provable, the spine is right. Which of flexibility and provability you need has to be settled before the arrangement can be.
Why BPMN
There are several ways to wire multiple agents together: a supervisor, a graph, a state machine, or code with the order baked in. As covered in Six Multi-Agent Workflow Patterns, the menu is not short.
BPMN was chosen on two criteria, neither of them expressiveness. A human task is a first-class element of the notation, and the notation has been the standard for drawing business processes for over twenty years.
The first is functional. Adding a human approval wait to a supervisor or graph arrangement means building the wait state and the resume point yourself. In BPMN the human task is already there and waiting and resuming are engine defaults.
The second is about people. Regulatory and audit staff have been reading process diagrams for years. Nobody has to learn a new notation to point at where the gate is. The deterministic-scaffold argument in Will No-Code Get Eaten, or Get More Valuable shows up here as a physical object. The scaffold around a language model’s judgment should be deterministic, and if it is a notation the organization already reads, one round of persuasion cost disappears.
Why the three axes fan out in parallel
On the canvas a parallel split sits behind the parser and the three axes separate. Exposing that split in the process definition was deliberate.
Scoring could have been one block with the result presented in three parts. Then one axis failing fails the whole diagnosis. In parallel, an axis blocked by an external reference problem still leaves the others, and the artifact records which axis was missing.
That property got used. Running without the embedding model means the handoff runtime metrics are not computed. The engine marks a degraded state, leaves a note reading “handoff metrics skipped, embedding model unavailable,” and finishes scoring on the ontology lookup alone. The 4.76 maximum with three RED from Part 3 is that state; with the metrics on it becomes 4.88 with four RED. Every ontology update is regression-checked against the degraded result, and the August cycle returned 3 RED for legal and 3 RED for credit underwriting, unchanged. Not making it all-or-nothing is what allowed a degraded state to exist at all.
What actually blocked the run
Three problems stood between the design and a working run. Two turned out to be platform issues and were filed on the public forum; one was packaging.
| Problem | Symptom | Handling |
|---|---|---|
| Solution publish | Deploying a solution containing a Maestro flow failed to find the tool factory | Routed through the debug execution path |
| Human task creation | Case folder and app folder binding mismatched, so task lookup failed | Demonstrated human review separately |
| Serverless packaging | The agent failed during environment preparation | Explicit wheel file selection and dependency split |
The third took longest, with a two-layer cause. The packaging configuration did not specify which files to ship, so the build could not determine its targets, and the heavy libraries used for retrieval and embedding were pinned as hard dependencies, pushing install size to 1.5GB.
The fix did both: name the paths to include, and move the heavy libraries into optional dependencies, leaving exactly two hard ones. That was possible because every heavy import is lazy and a hash-based fallback exists when embeddings are absent. The credit underwriting sample was run in a clean virtual environment with none of those libraries present, confirming the human-review-required verdict still came out correctly, before the version was bumped.

The first two were worked around. With solution publish blocked, the process ran through the debug path; with automatic human task creation blocked, the diagnosis run and the approval screen were shown separately. The workaround is not the point; whether what was being verified still got verified is. The thing to confirm was that the repackaged agent runs inside the execution environment, and that is confirmed on the debug path too.
What came out of these three is less a technical lesson than a sense of schedule. Committing to a process engine as the spine means passing through its deployment paths, folder structures, and packaging rules. Having diagnosis code that runs locally and having it run inside the platform are different stages, and the second can take longer. In return, state management, waiting and resuming, human tasks, and execution history do not have to be built.
What was verified and what was not
The rule kept in the deck and the submission was to quote numbers only for what can be shown on screen.
Verified: with the repackaged build, the coded agent completes inside the execution environment in roughly 33 seconds without errors, the return value reaches the gateway and splits the path, and the process resumes after approval on the human review path. With metrics on, the credit underwriting sample surfaces four nodes over threshold.
Not verified, also recorded: the judge metric defaults to a mock backend, so a real judgment requires naming one. Observability integration is unresolved. A peer review module that has a separate model re-examine the diagnosis exists as a file but is not called by the engine. The retrieval quality figures for graph-based search were withdrawn: the gold set and the retriever’s filter derived from the same source, so the filter matched the gold set trivially, which is not an independent measurement. The graph itself, 8,287 nodes and 12,317 edges, remains valid; the performance numbers are pending re-measurement.
Those numbers were pulled from the submission and the deck for a simple reason: put in a number with no on-screen evidence and every other number gets doubted with it.
Closing - when the gate is a picture
This series started from the observation that pre-deployment review lives only inside consulting engagements, split that review into a scoring table and a gate, and ended by placing the gate into a process definition.
One thing runs through all four parts. Move judgment out of a person’s head into a table, keep the table as data rather than code, and keep the gate condition as a sentence on a picture rather than as code. The direction of each move is the same. Put judgment somewhere it can be read and re-running and proving come with it.
Consulting diagnosis was expensive not because a human judged, but because that judgment had never come out. As a table it can be re-run; as a gateway name it can be read by regulatory staff. The remaining value attaches to keeping the table current.
Sources
- Process definition
scripts/uipath/bpmn_diagnosis_workflow.bpmn(18 flow objects, 20 flows), agent entry pointscripts/uipath/coded_agent_wrapper.py(public repository) - Gate conditions in
scripts/core/tools.py(evaluate_hitl), thresholds inscripts/core/contracts.py(HitlThresholds) - Submission page: FDE Agent on Devpost
- The two platform issues are filed on the official UiPath community forum (solution deployment, and human task lookup during case plan debugging)
Related Posts

The Riskiest Node Was Auto-Approval - Catching Silent Over-Trust with a Subtraction
Two workflows from different domains, scored on the same table, put their top scores on nodes of the same character: the ones where the human lets go. One subtraction that catches silent over-trust, the arithmetic that pushes a 3.6 node to 4.9, and why being red is not the same as reaching a human.

The Axis No Public Dataset Had Got the Largest Weight - A 36-Cell Risk Ontology
Scoring an AI workflow node by node needs a scoring table first. The general-failure and security axes came from OWASP, MITRE ATLAS, and MIT material, but the third axis, the one that looks between nodes, existed in no public framework. Why it got 0.4, and why only its score can rise mid-run.

You Find Out Where It Breaks After You Ship - Moving the Pre-Deployment Check into a Process
Pre-deployment risk review for AI workflows lives inside consulting engagements: one to two senior-weeks per workflow, not re-runnable. Why this quadrant stayed empty, when the regulatory deadlines actually land, and what remains once the check becomes a single governed run.