
1
00:00:00,000 –> 00:00:01,920
Most organizations treat the power platform
2
00:00:01,920 –> 00:00:03,920
like a harmless productivity toy.
3
00:00:03,920 –> 00:00:06,120
Drag some boxes, automate a few emails,
4
00:00:06,120 –> 00:00:08,080
call it digital transformation.
5
00:00:08,080 –> 00:00:11,440
Then it scales, and the same logic that felt clean at 10 runs
6
00:00:11,440 –> 00:00:13,800
a day becomes a pile of exceptions at 10,000.
7
00:00:13,800 –> 00:00:15,040
That’s not success.
8
00:00:15,040 –> 00:00:16,600
That’s unpriced complexity.
9
00:00:16,600 –> 00:00:19,760
The hybrid mandate is simple.
10
00:00:19,760 –> 00:00:21,680
Power platform is the orchestration tier.
11
00:00:21,680 –> 00:00:23,080
Python is the execution tier.
12
00:00:23,080 –> 00:00:24,320
Azure is the governance tier,
13
00:00:24,320 –> 00:00:26,200
separate coordination from computation,
14
00:00:26,200 –> 00:00:28,800
and rapid all in identity, network boundaries, logging,
15
00:00:28,800 –> 00:00:32,160
and policy so it stays governable after the hype dies.
16
00:00:32,160 –> 00:00:33,880
The foundational misunderstanding.
17
00:00:33,880 –> 00:00:36,520
Power platform as a tool, not a control plane.
18
00:00:36,520 –> 00:00:39,000
The foundational misunderstanding is that power platform
19
00:00:39,000 –> 00:00:41,480
is a tool in the same way Excel is a tool.
20
00:00:41,480 –> 00:00:43,920
A thing people use, a thing that sits at the edge.
21
00:00:43,920 –> 00:00:44,880
Something optional.
22
00:00:44,880 –> 00:00:46,480
That is not what you’re deploying.
23
00:00:46,480 –> 00:00:50,200
In architectural terms, power platform is a control plane.
24
00:00:50,200 –> 00:00:51,960
A distributed decision engine
25
00:00:51,960 –> 00:00:55,680
that coordinates data movement, actions, approvals, identities,
26
00:00:55,680 –> 00:00:57,720
and connector calls across your tenant.
27
00:00:57,720 –> 00:00:59,120
It doesn’t just automate work.
28
00:00:59,120 –> 00:01:01,360
It defines how work is allowed to happen
29
00:01:01,360 –> 00:01:02,920
and who is allowed to trigger it
30
00:01:02,920 –> 00:01:05,080
and which data is allowed to cross which boundary.
31
00:01:05,080 –> 00:01:07,400
That distinction matters because the moment you treat
32
00:01:07,400 –> 00:01:09,880
a control plane like a toy, you stop designing it.
33
00:01:09,880 –> 00:01:12,240
And when you stop designing it, the system designs itself.
34
00:01:12,240 –> 00:01:13,240
It always does.
35
00:01:13,240 –> 00:01:15,720
When people say, “Power Automate is just workflows.”
36
00:01:15,720 –> 00:01:17,160
What they’re really saying is,
37
00:01:17,160 –> 00:01:20,520
“I don’t want to own the consequences of a workflow runtime
38
00:01:20,520 –> 00:01:22,960
that can call a thousand external systems
39
00:01:22,960 –> 00:01:26,400
with the privileges of whoever clicked create connection.”
40
00:01:27,440 –> 00:01:29,920
The platform is not fragile, your assumptions are.
41
00:01:29,920 –> 00:01:31,720
Here’s where decisions actually happen.
42
00:01:31,720 –> 00:01:33,720
Identity determines what a flow can do,
43
00:01:33,720 –> 00:01:35,640
connectors determine what a flow can reach,
44
00:01:35,640 –> 00:01:37,520
environments determine where it can be built
45
00:01:37,520 –> 00:01:38,640
and who can see it.
46
00:01:38,640 –> 00:01:41,000
DLP determines which connectors can be paired,
47
00:01:41,000 –> 00:01:43,040
solutions and ALM determine whether the thing
48
00:01:43,040 –> 00:01:45,280
running in production is an artifact with intent
49
00:01:45,280 –> 00:01:47,600
or just a screenshot of last month’s prototype.
50
00:01:47,600 –> 00:01:50,000
Most organizations focus on the visible part,
51
00:01:50,000 –> 00:01:52,480
the canvas, the steps, the triggers.
52
00:01:52,480 –> 00:01:53,640
That’s the UI.
53
00:01:53,640 –> 00:01:55,760
The real architecture is the graph behind it.
54
00:01:55,760 –> 00:01:57,600
Entry Identity’s delegated permissions,
55
00:01:57,600 –> 00:01:59,600
connection references, environment roles,
56
00:01:59,600 –> 00:02:01,640
dataverse security and policy objects
57
00:02:01,640 –> 00:02:04,240
that live in admin portals nobody wants to open.
58
00:02:04,240 –> 00:02:05,240
So what goes wrong?
59
00:02:05,240 –> 00:02:06,120
Entropy.
60
00:02:06,120 –> 00:02:09,040
Because low-code teams under pressure don’t build systems.
61
00:02:09,040 –> 00:02:09,920
They build exceptions.
62
00:02:09,920 –> 00:02:12,840
Just this one connector, just this one bypassed it,
63
00:02:12,840 –> 00:02:14,800
just put the credential in a variable.
64
00:02:14,800 –> 00:02:16,200
Just add a condition.
65
00:02:16,200 –> 00:02:17,360
Each one feels small.
66
00:02:17,360 –> 00:02:18,600
None of them is revisited.
67
00:02:18,600 –> 00:02:21,160
Over time, the exceptions become the architecture
68
00:02:21,160 –> 00:02:23,120
and once exceptions become the architecture,
69
00:02:23,120 –> 00:02:26,040
you’re no longer operating a deterministic security model.
70
00:02:26,040 –> 00:02:27,640
You’re operating a probabilistic one.
71
00:02:27,640 –> 00:02:29,640
The system still runs, but you can’t predict
72
00:02:29,640 –> 00:02:31,160
its behavior underdrift.
73
00:02:31,160 –> 00:02:33,040
When people leave, when tokens expire,
74
00:02:33,040 –> 00:02:35,760
when licensing changes, when a connector update breaks
75
00:02:35,760 –> 00:02:37,760
a payload, when throttles kick in,
76
00:02:37,760 –> 00:02:40,400
when a maker copies a flow to fix it quickly
77
00:02:40,400 –> 00:02:43,080
and accidentally creates a parallel universe.
78
00:02:43,080 –> 00:02:46,200
This is why it works is not the same as it is governable.
79
00:02:46,200 –> 00:02:48,240
A flow can work while being unreviewable.
80
00:02:48,240 –> 00:02:50,560
It can work while having no owner you can contact.
81
00:02:50,560 –> 00:02:51,960
It can work while being impossible
82
00:02:51,960 –> 00:02:53,440
to reproduce in another environment.
83
00:02:53,440 –> 00:02:55,920
It can work while quietly moving data from dataverse
84
00:02:55,920 –> 00:02:57,280
to a consumer connector.
85
00:02:57,280 –> 00:03:00,400
Because somebody built it in the default environment at 2am.
86
00:03:00,400 –> 00:03:02,840
It can work while your incident response team
87
00:03:02,840 –> 00:03:05,800
has no correlated logs and no idea whether the last run
88
00:03:05,800 –> 00:03:08,040
failed because of data, permissions, throttling
89
00:03:08,040 –> 00:03:10,000
or a transient back end issue.
90
00:03:10,000 –> 00:03:10,960
That’s the comfort trap.
91
00:03:10,960 –> 00:03:12,280
Success hides failure modes.
92
00:03:12,280 –> 00:03:13,760
Now add Python to the story.
93
00:03:13,760 –> 00:03:17,400
The naive question is, can power automate call Python?
94
00:03:17,400 –> 00:03:18,080
Sure.
95
00:03:18,080 –> 00:03:19,840
People already do it with file watches,
96
00:03:19,840 –> 00:03:22,800
one drive polling, local scripts, random service accounts
97
00:03:22,800 –> 00:03:24,960
and whatever laptop happens to be online.
98
00:03:24,960 –> 00:03:27,040
But the real question is, where does Python belong
99
00:03:27,040 –> 00:03:28,640
and what does it do to your control plane?
100
00:03:28,640 –> 00:03:30,520
Because Python isn’t just code.
101
00:03:30,520 –> 00:03:33,480
It’s an execution environment, packages, dependencies,
102
00:03:33,480 –> 00:03:36,480
runtime patching, outbound calls, secret handling
103
00:03:36,480 –> 00:03:37,920
and operational ownership.
104
00:03:37,920 –> 00:03:40,200
If you bolt it onto power platform without boundaries,
105
00:03:40,200 –> 00:03:41,800
you don’t get a hybrid architecture.
106
00:03:41,800 –> 00:03:44,800
You get a shadow runtime with undefined responsibility.
107
00:03:44,800 –> 00:03:46,240
That is how governance disappears,
108
00:03:46,240 –> 00:03:48,320
not with malice but with convenience.
109
00:03:48,320 –> 00:03:51,600
So the right framing is this, power platform orchestrates.
110
00:03:51,600 –> 00:03:54,240
It roots, approves, schedules, notifies
111
00:03:54,240 –> 00:03:55,920
and handles human touch points.
112
00:03:55,920 –> 00:03:59,920
Python executes, it transforms, validates, deduplicates, scores
113
00:03:59,920 –> 00:04:01,640
and computes in a deterministic way
114
00:04:01,640 –> 00:04:03,680
that doesn’t belong inside a flow designer.
115
00:04:03,680 –> 00:04:06,360
As your governs, it provides the enforcement layer.
116
00:04:06,360 –> 00:04:09,440
Identity primitives, network containment, secrets,
117
00:04:09,440 –> 00:04:13,080
observability, policy and life cycle control.
118
00:04:13,080 –> 00:04:15,240
Treat power platform as a control plane
119
00:04:15,240 –> 00:04:17,120
and you start asking better questions.
120
00:04:17,120 –> 00:04:18,280
Who is the principal?
121
00:04:18,280 –> 00:04:20,440
Which identity is calling, which service?
122
00:04:20,440 –> 00:04:21,560
What is the network path?
123
00:04:21,560 –> 00:04:22,520
Where do secrets live?
124
00:04:22,520 –> 00:04:24,280
What does internal mean?
125
00:04:24,280 –> 00:04:25,040
Where are the logs?
126
00:04:25,040 –> 00:04:27,360
And can they be correlated across tiers?
127
00:04:27,360 –> 00:04:29,960
What is the contract between orchestration and execution?
128
00:04:29,960 –> 00:04:31,920
What happens when this scales by 10 times?
129
00:04:31,920 –> 00:04:33,480
Most people never ask those questions
130
00:04:33,480 –> 00:04:34,720
because the first flow works.
131
00:04:34,720 –> 00:04:38,000
Then the second one works, then you have 50, then you have 500,
132
00:04:38,000 –> 00:04:40,760
then the audit shows up and everyone suddenly discovers
133
00:04:40,760 –> 00:04:43,280
they’ve been running a distributed integration platform
134
00:04:43,280 –> 00:04:44,600
with no architecture.
135
00:04:44,600 –> 00:04:46,640
And this is the moment the low-code team
136
00:04:46,640 –> 00:04:48,760
hits the ceiling, not a technical ceiling,
137
00:04:48,760 –> 00:04:51,200
a governance ceiling, the low-code ceiling
138
00:04:51,200 –> 00:04:53,680
when flows become data pipelines by accident.
139
00:04:53,680 –> 00:04:55,440
This is where the story always turns.
140
00:04:55,440 –> 00:04:57,880
The first few flows are fine, send a team’s message,
141
00:04:57,880 –> 00:05:00,360
create a task, root an approval, write a row,
142
00:05:00,360 –> 00:05:02,480
then the business starts trusting the automation
143
00:05:02,480 –> 00:05:05,480
and trust turns into load and load turns into ambition.
144
00:05:05,480 –> 00:05:07,600
Suddenly the flow isn’t automation anymore.
145
00:05:07,600 –> 00:05:10,320
It’s an accidental data pipeline, it’s passing CSVs,
146
00:05:10,320 –> 00:05:12,480
it’s normalizing Excel tabs, it’s doing lookups
147
00:05:12,480 –> 00:05:14,960
across multiple systems, it’s joining data,
148
00:05:14,960 –> 00:05:16,320
it’s deduplicating,
149
00:05:16,320 –> 00:05:19,520
it’s trying to behave like an ETL tool, a rules engine
150
00:05:19,520 –> 00:05:21,840
and a batch processor, inside a designer
151
00:05:21,840 –> 00:05:24,840
that was built to coordinate steps, not compute.
152
00:05:24,840 –> 00:05:26,800
You can tell you’ve hit the ceiling by the symptoms
153
00:05:26,800 –> 00:05:29,000
and they’re consistent across tenants.
154
00:05:29,000 –> 00:05:30,120
There’s the spreadsheet phase,
155
00:05:30,120 –> 00:05:32,520
someone drops a file into one drive or share point,
156
00:05:32,520 –> 00:05:34,720
the flow reads rows and everything is fine
157
00:05:34,720 –> 00:05:36,040
until the file isn’t fine.
158
00:05:36,040 –> 00:05:38,960
Extra columns embedded commas, we are date formats.
159
00:05:38,960 –> 00:05:40,760
Empty rows that aren’t actually empty,
160
00:05:40,760 –> 00:05:42,800
a total line somebody forgot to delete.
161
00:05:42,800 –> 00:05:44,840
Now the flow has 10 string replacements
162
00:05:44,840 –> 00:05:47,280
and a set of conditions that look like a legal disclaimer.
163
00:05:47,280 –> 00:05:49,080
Then come the loops, nested loops,
164
00:05:49,080 –> 00:05:51,120
apply to each inside, apply to each,
165
00:05:51,120 –> 00:05:53,880
a scope inside a scope because somebody needed a try,
166
00:05:53,880 –> 00:05:55,960
catch, another scope because someone needed
167
00:05:55,960 –> 00:05:57,880
to continue on error.
168
00:05:57,880 –> 00:06:00,480
And now the flow run history is basically a crime scene.
169
00:06:00,480 –> 00:06:03,640
600 actions, three retries, four parallel branches
170
00:06:03,640 –> 00:06:06,560
and a final terminate with a message that tells you nothing.
171
00:06:06,560 –> 00:06:08,720
This might seem like a maker problem, it isn’t.
172
00:06:08,720 –> 00:06:10,280
It’s a platform economics problem.
173
00:06:10,280 –> 00:06:12,400
In power automate, every additional action
174
00:06:12,400 –> 00:06:14,280
is an unpriced maintenance contract.
175
00:06:14,280 –> 00:06:15,880
You don’t pay the cost when you build it.
176
00:06:15,880 –> 00:06:18,760
You pay it when you debug it, version it, secure it
177
00:06:18,760 –> 00:06:20,760
and explain it to someone who didn’t design it.
178
00:06:20,760 –> 00:06:22,240
And the platform encourages this
179
00:06:22,240 –> 00:06:25,240
because the UI makes every step feel equally cheap.
180
00:06:25,240 –> 00:06:27,440
One more action, one more condition, one more compose,
181
00:06:27,440 –> 00:06:28,560
it’s fine, it isn’t.
182
00:06:28,560 –> 00:06:30,360
Because flows don’t give you determinism.
183
00:06:30,360 –> 00:06:31,760
They give you last run.
184
00:06:31,760 –> 00:06:34,120
When something breaks, you get a screenshot of a failed action
185
00:06:34,120 –> 00:06:36,200
and a payload that’s half context, half noise
186
00:06:36,200 –> 00:06:38,720
and you’re expected to reverse engineer intent
187
00:06:38,720 –> 00:06:39,880
from the remains.
188
00:06:39,880 –> 00:06:42,640
And changes don’t carry version intent by default.
189
00:06:42,640 –> 00:06:45,800
A maker tweaks in expression, the flow runs, the incident stops
190
00:06:45,800 –> 00:06:48,000
and nobody can tell you what changed, why it changed
191
00:06:48,000 –> 00:06:49,920
or whether it created a new failure mode
192
00:06:49,920 –> 00:06:51,560
that just hasn’t been triggered yet.
193
00:06:51,560 –> 00:06:53,560
The system becomes a set of invisible forks.
194
00:06:53,560 –> 00:06:55,000
This is also where platform limits
195
00:06:55,000 –> 00:06:58,160
quietly convert logic into workaround engineering.
196
00:06:58,160 –> 00:07:01,040
Connector throttles don’t care about your business priority.
197
00:07:01,040 –> 00:07:03,080
Run limits don’t care about your deadline.
198
00:07:03,080 –> 00:07:06,120
Large payload limits don’t care that it’s just a spreadsheet.
199
00:07:06,120 –> 00:07:08,680
So people start engineering around the constraints,
200
00:07:08,680 –> 00:07:11,080
chunking arrays, splitting files, delaying steps,
201
00:07:11,080 –> 00:07:13,240
adding weights, switching to concurrency,
202
00:07:13,240 –> 00:07:16,080
then turning concurrency off because it causes duplicates,
203
00:07:16,080 –> 00:07:18,760
then adding a do not run twice flag in dataverse
204
00:07:18,760 –> 00:07:20,560
that fails under race conditions.
205
00:07:20,560 –> 00:07:23,920
And the weird part is, all of these workarounds look like progress.
206
00:07:23,920 –> 00:07:25,800
They’re not progress, they’re symptoms of using
207
00:07:25,800 –> 00:07:28,040
an orchestration engine as a compute engine.
208
00:07:28,040 –> 00:07:31,320
So when someone asks, can power automate kick off Python?
209
00:07:31,320 –> 00:07:34,040
They’re usually asking the wrong question with the right instinct.
210
00:07:34,040 –> 00:07:36,520
The instinct is that computation needs a real runtime.
211
00:07:36,520 –> 00:07:39,040
The wrong part is thinking the integration is the hard problem.
212
00:07:39,040 –> 00:07:40,200
The integration is easy.
213
00:07:40,200 –> 00:07:41,280
The boundary is the problem.
214
00:07:41,280 –> 00:07:43,960
Because the moment you bolt Python onto a flow without deciding
215
00:07:43,960 –> 00:07:46,480
where it lives, you’ve created an unknown execution tier.
216
00:07:46,480 –> 00:07:48,200
If it’s a script on someone’s laptop,
217
00:07:48,200 –> 00:07:50,760
you just made availability dependent on a human.
218
00:07:50,760 –> 00:07:54,240
If it’s a file watcher, you just made your control plane depend on polling.
219
00:07:54,240 –> 00:07:56,440
If it’s a service account, you just planted a credential
220
00:07:56,440 –> 00:07:58,200
that will outlive the person who created it.
221
00:07:58,200 –> 00:08:00,880
If it writes directly back to dataverse using ad hoc tokens,
222
00:08:00,880 –> 00:08:03,640
you just bypass the governance posture you thought you had.
223
00:08:03,640 –> 00:08:07,320
This is why the low-code ceiling is not the moment flows can’t do the work.
224
00:08:07,320 –> 00:08:09,480
It’s the moment the only way to keep doing the work
225
00:08:09,480 –> 00:08:12,960
is to add more actions, more exceptions, and more hidden dependencies.
226
00:08:12,960 –> 00:08:14,920
That is architectural erosion in real time.
227
00:08:14,920 –> 00:08:17,040
So the real question isn’t can it call Python?
228
00:08:17,040 –> 00:08:19,560
The real question is, what stays in power platform
229
00:08:19,560 –> 00:08:22,560
because it’s orchestration and what leaves because it’s execution?
230
00:08:22,560 –> 00:08:26,400
If you don’t answer that, your flows will keep mutating into pipelines by accident
231
00:08:26,400 –> 00:08:31,240
and you’ll keep paying for it in the only currency that matters in production and baguity.
232
00:08:31,240 –> 00:08:34,720
And from here, the model has to become explicit or the entropy wins.
233
00:08:34,720 –> 00:08:36,360
Define the three tier model.
234
00:08:36,360 –> 00:08:39,680
So define the model explicitly before you integrate anything.
235
00:08:39,680 –> 00:08:43,360
Because if you don’t define tiers, you don’t get a hybrid architecture.
236
00:08:43,360 –> 00:08:44,880
You get a hybrid blame game.
237
00:08:44,880 –> 00:08:46,880
Power platform is the orchestration tier.
238
00:08:46,880 –> 00:08:48,200
Python is the execution tier.
239
00:08:48,200 –> 00:08:49,440
Azure is the governance tier.
240
00:08:49,440 –> 00:08:51,440
And yes, these words sound like a diagram,
241
00:08:51,440 –> 00:08:54,320
but treat them as ownership boundaries, not shapes on a slide.
242
00:08:54,320 –> 00:08:56,880
Each tier exists because it is good at one thing
243
00:08:56,880 –> 00:08:59,040
and dangerously mediocre at the other two.
244
00:08:59,040 –> 00:09:01,240
Start with orchestration.
245
00:09:01,240 –> 00:09:03,360
Power platform excels at coordination.
246
00:09:03,360 –> 00:09:08,000
Triggers, rooting, approvals, human in the loop steps, notifications,
247
00:09:08,000 –> 00:09:10,320
exception handling that a business can understand
248
00:09:10,320 –> 00:09:13,280
and state tracking that lives close to the process owners.
249
00:09:13,280 –> 00:09:17,360
It’s also where connector policy and environment scoping can actually enforce behavior at scale.
250
00:09:17,360 –> 00:09:19,680
The orchestration tier should do three jobs.
251
00:09:19,680 –> 00:09:21,640
Decide that work needs to happen.
252
00:09:21,640 –> 00:09:23,200
Decide who is allowed to approve it
253
00:09:23,200 –> 00:09:25,240
and decide whether results should be recorded.
254
00:09:25,240 –> 00:09:25,760
That’s it.
255
00:09:25,760 –> 00:09:30,800
The orchestration tier is not where you do heavy passing, complex validation, bulk data shaping
256
00:09:30,800 –> 00:09:32,920
or probabilistic, let’s see what happens loops.
257
00:09:32,920 –> 00:09:36,720
Because once you do that, the flow stops being coordination and becomes computation
258
00:09:36,720 –> 00:09:39,840
and you lose determinism, version intent and debuggability.
259
00:09:39,840 –> 00:09:42,000
Now the execution tier.
260
00:09:42,000 –> 00:09:45,160
Python exists here because execution needs determinism.
261
00:09:45,160 –> 00:09:49,240
It needs a real runtime, real libraries, real testing, real error handling,
262
00:09:49,240 –> 00:09:52,480
real dependency management and real performance characteristics.
263
00:09:52,480 –> 00:09:55,800
This tier is where you do transforms, normalization, deduplication,
264
00:09:55,800 –> 00:09:58,760
model inference, scoring, enrichment and batch strategy.
265
00:09:58,760 –> 00:10:01,280
It’s where you can implement idempotency
266
00:10:01,280 –> 00:10:04,920
as code, not as a pile of flags inside a low code designer.
267
00:10:04,920 –> 00:10:08,520
It’s where you can unit test the rules that decide whether a row is valid,
268
00:10:08,520 –> 00:10:11,280
a record should be merged or a payload should be rejected.
269
00:10:11,280 –> 00:10:14,200
And the critical point, the execution tier should behave like a service,
270
00:10:14,200 –> 00:10:15,560
not a script, not a sidecar.
271
00:10:15,560 –> 00:10:19,600
A service has a contract, a service has versions, a service has clear inputs and outputs.
272
00:10:19,600 –> 00:10:25,200
A service can be patched without asking makers to open 50 flows and edit expressions they don’t understand.
273
00:10:25,200 –> 00:10:28,800
A service can be monitored, a service can be throttled intentionally
274
00:10:28,800 –> 00:10:33,680
and a service can be owned by a team that is accountable for its behavior in production.
275
00:10:33,680 –> 00:10:35,640
That’s what Python is for in this model,
276
00:10:35,640 –> 00:10:39,920
deterministic compute that stays stable while the orchestration changes around it.
277
00:10:39,920 –> 00:10:41,840
Now the governance tier.
278
00:10:41,840 –> 00:10:48,080
As you exist here because somebody has to enforce reality, identity, network boundaries, secrets,
279
00:10:48,080 –> 00:10:52,080
observability, policy, cost controls, life cycle.
280
00:10:52,080 –> 00:10:57,000
The governance tier is the place where you stop trusting its internal as a security strategy
281
00:10:57,000 –> 00:11:00,200
and start making it true with control plane primitives.
282
00:11:00,200 –> 00:11:02,520
This is where enter ID becomes non-negotiable.
283
00:11:02,520 –> 00:11:06,040
Non-interactive workloads should authenticate as principles, not as people.
284
00:11:06,040 –> 00:11:11,000
This is where key vault, managed identities and secret rotation stop being nice to have
285
00:11:11,000 –> 00:11:13,000
and become basic operational hygiene.
286
00:11:13,000 –> 00:11:17,640
This is where network containment turns reachable into a governed property, not a convenience.
287
00:11:17,640 –> 00:11:21,800
And this is where logs and metrics cross tier, so incident response becomes a query,
288
00:11:21,800 –> 00:11:22,880
not a group chat.
289
00:11:22,880 –> 00:11:25,760
A lot of teams try to skip this tier because it doesn’t ship features.
290
00:11:25,760 –> 00:11:26,560
That’s the mistake.
291
00:11:26,560 –> 00:11:28,320
The governance tier doesn’t ship features.
292
00:11:28,320 –> 00:11:29,800
It prevents entropy.
293
00:11:29,800 –> 00:11:33,160
An entropy is what kills your features after they succeed.
294
00:11:33,160 –> 00:11:38,200
Now here’s what changes when you adopt the three tier model, not capability, ownership.
295
00:11:38,200 –> 00:11:42,320
In a low-code purity world, the maker owns everything by default, the trigger, the logic,
296
00:11:42,320 –> 00:11:46,200
the data shaping, the credentials, the error handling, the notifications, and the downstream
297
00:11:46,200 –> 00:11:47,200
rights.
298
00:11:47,200 –> 00:11:49,480
That feels empowering right up until it becomes unreviewable.
299
00:11:49,480 –> 00:11:54,120
In the three tier model, the maker owns orchestration, engineers own execution, platform
300
00:11:54,120 –> 00:11:56,440
and security teams own governance.
301
00:11:56,440 –> 00:12:02,000
And the seams between them are formal, authentication, authorization, network paths, contracts and
302
00:12:02,000 –> 00:12:03,000
correlated logs.
303
00:12:03,000 –> 00:12:05,680
That distinction matters because it creates survivability.
304
00:12:05,680 –> 00:12:07,840
When someone leaves, the principle still exists.
305
00:12:07,840 –> 00:12:10,480
When a package needs patching, the service is updated once.
306
00:12:10,480 –> 00:12:14,680
When an audit asks how data moves, you can answer with boundaries, not with hope.
307
00:12:14,680 –> 00:12:18,720
When scale arrives, throttling and queues exist where they belong, not embedded as delay
308
00:12:18,720 –> 00:12:20,840
30 seconds inside a flow.
309
00:12:20,840 –> 00:12:24,160
And the punchline is simple, power platform doesn’t lose value in this model.
310
00:12:24,160 –> 00:12:25,160
It gains value.
311
00:12:25,160 –> 00:12:29,440
Because now it can stay what it actually is, a control plane for business process.
312
00:12:29,440 –> 00:12:31,760
While Python does what it’s always done, compute.
313
00:12:31,760 –> 00:12:36,000
And Azure does what enterprises always forget they need until after the incident.
314
00:12:36,000 –> 00:12:37,200
In force.
315
00:12:37,200 –> 00:12:40,080
The anti-pattern Python is a sidecar in the shadows.
316
00:12:40,080 –> 00:12:43,200
The anti-pattern looks innocent because it usually starts as a demo.
317
00:12:43,200 –> 00:12:47,440
Someone proves power automate can trigger Python by dropping a file in one drive, then a
318
00:12:47,440 –> 00:12:50,160
local script notices the file and does the work.
319
00:12:50,160 –> 00:12:53,320
Or Python triggers a flow by calling an HTTP endpoint.
320
00:12:53,320 –> 00:12:56,960
It works, everyone claps, the organization calls it innovation, what they actually build
321
00:12:56,960 –> 00:12:58,400
is a sidecar in the shadows.
322
00:12:58,400 –> 00:12:59,680
It’s not an execution tier.
323
00:12:59,680 –> 00:13:01,000
It’s a haunted extension cord.
324
00:13:01,000 –> 00:13:02,960
The first variant is the file watcher.
325
00:13:02,960 –> 00:13:04,600
Power automate writes a file to a folder.
326
00:13:04,600 –> 00:13:06,080
Python pulls the folder.
327
00:13:06,080 –> 00:13:07,320
When a file appears it runs.
328
00:13:07,320 –> 00:13:10,240
The weird part is how quickly this becomes production behavior.
329
00:13:10,240 –> 00:13:12,120
Not because it’s good, because it’s easy.
330
00:13:12,120 –> 00:13:15,800
And once a business process depends on it, nobody wants to touch it.
331
00:13:15,800 –> 00:13:18,840
But a polling script is a governance failure disguised as automation.
332
00:13:18,840 –> 00:13:19,840
It has no contract.
333
00:13:19,840 –> 00:13:21,280
It has no authenticated caller.
334
00:13:21,280 –> 00:13:23,160
It has no explicit authorization model.
335
00:13:23,160 –> 00:13:25,440
It has no deterministic retry behavior.
336
00:13:25,440 –> 00:13:29,520
It has wild true and asleep timer, which is basically the architectural equivalent of leaving
337
00:13:29,520 –> 00:13:32,800
a car idling because you don’t trust it to start again.
338
00:13:32,800 –> 00:13:34,240
Then you get the next variant.
339
00:13:34,240 –> 00:13:36,320
Local scripts on laptops or jump boxes.
340
00:13:36,320 –> 00:13:38,880
The flow writes a file, a scheduled task runs Python.
341
00:13:38,880 –> 00:13:40,880
A team shares the script in TeamsChat.
342
00:13:40,880 –> 00:13:42,960
Somebody pins a message with, don’t delete this.
343
00:13:42,960 –> 00:13:47,440
And now the availability of your automation depends on whether a workstation reboots during
344
00:13:47,440 –> 00:13:48,440
patch Tuesday.
345
00:13:48,440 –> 00:13:50,200
This is what incident reviews sound like.
346
00:13:50,200 –> 00:13:51,200
It worked yesterday.
347
00:13:51,200 –> 00:13:53,640
No, a person’s workstation worked yesterday.
348
00:13:53,640 –> 00:13:57,840
The third variant is the service account because eventually somebody gets tired of MFA
349
00:13:57,840 –> 00:13:59,600
prompts and broken connections.
350
00:13:59,600 –> 00:14:04,160
So they create automation at company, com, granted broad access and store the password
351
00:14:04,160 –> 00:14:06,480
somewhere that feels private until it isn’t.
352
00:14:06,480 –> 00:14:08,960
That account becomes the keystone of the whole arrangement.
353
00:14:08,960 –> 00:14:10,160
It authenticates the script.
354
00:14:10,160 –> 00:14:11,560
It authenticates the connectors.
355
00:14:11,560 –> 00:14:14,920
It authenticates the downstream rights and nobody can tell you who’s responsible for
356
00:14:14,920 –> 00:14:15,920
it.
357
00:14:15,920 –> 00:14:18,240
In architectural terms, you didn’t solve authentication.
358
00:14:18,240 –> 00:14:22,680
You manufactured an entropy generator and yes, the sidecar can be in the cloud and still
359
00:14:22,680 –> 00:14:24,520
be the same anti-pattern.
360
00:14:24,520 –> 00:14:29,480
A container running Python with a public endpoint, a function app with no network containment,
361
00:14:29,480 –> 00:14:32,760
a web hook that accepts anonymous requests because it’s just internal.
362
00:14:32,760 –> 00:14:36,440
It is a key in a config file because we’ll move it to Key Vault later.
363
00:14:36,440 –> 00:14:37,440
Later never arrives.
364
00:14:37,440 –> 00:14:40,080
Later is where security debt goes to retire comfortably.
365
00:14:40,080 –> 00:14:42,520
This is why sidecar Python fails in incident reviews.
366
00:14:42,520 –> 00:14:44,480
Ownership and boundaries are undefined.
367
00:14:44,480 –> 00:14:45,640
Who owns the runtime?
368
00:14:45,640 –> 00:14:48,120
Who patches the dependencies when a CVE drops?
369
00:14:48,120 –> 00:14:49,120
Who rotates the secret?
370
00:14:49,120 –> 00:14:50,120
Who reviews the code?
371
00:14:50,120 –> 00:14:52,080
Who decides what outbound calls are allowed?
372
00:14:52,080 –> 00:14:54,240
Who has the logs when it fails at 3am?
373
00:14:54,240 –> 00:14:55,600
And the most important question?
374
00:14:55,600 –> 00:14:59,680
Who is accountable when the script quietly exfiltrates data to somewhere that was never
375
00:14:59,680 –> 00:15:01,000
modeled?
376
00:15:01,000 –> 00:15:04,640
Because somebody imported a library that phones home for updates.
377
00:15:04,640 –> 00:15:06,600
The operational rod shows up first.
378
00:15:06,600 –> 00:15:08,800
The script works until a package version changes.
379
00:15:08,800 –> 00:15:10,360
It works until the OS updates.
380
00:15:10,360 –> 00:15:12,240
It works until the directory path changes.
381
00:15:12,240 –> 00:15:15,280
It works until the one drive sync client decides its offline.
382
00:15:15,280 –> 00:15:18,080
It works until the maker renames a file and the parser breaks.
383
00:15:18,080 –> 00:15:20,800
It works until concurrency shows up in two runs collide.
384
00:15:20,800 –> 00:15:24,920
And when it fails, it fails in a place the power platform team can’t see.
385
00:15:24,920 –> 00:15:28,880
Outside the run history, outside the connector logs, outside the environment telemetry.
386
00:15:28,880 –> 00:15:33,000
Your control plane loses observability exactly where you introduced complexity.
387
00:15:33,000 –> 00:15:34,320
Then the security rod shows up.
388
00:15:34,320 –> 00:15:36,640
The data path becomes outbound by accident.
389
00:15:36,640 –> 00:15:40,040
Dataverse data gets written to files because that was the easiest handoff.
390
00:15:40,040 –> 00:15:43,760
Those files land in places with consumer sync clients, retention policies you didn’t
391
00:15:43,760 –> 00:15:46,040
design and access you didn’t review.
392
00:15:46,040 –> 00:15:50,280
For the Python script calls back into power automate through an HTTP trigger that has no
393
00:15:50,280 –> 00:15:53,680
meaningful authorization beyond, you know the URL.
394
00:15:53,680 –> 00:15:56,760
That’s not integration, that’s a back door you forgot you created.
395
00:15:56,760 –> 00:16:01,560
And the irony is that the bidirectional arrow, the thing people love to show on slides, can
396
00:16:01,560 –> 00:16:02,840
be real and safe.
397
00:16:02,840 –> 00:16:05,360
But only if you treat it like a tier boundary with enforcement.
398
00:16:05,360 –> 00:16:08,280
A side car is what you get when you treat Python like a hack.
399
00:16:08,280 –> 00:16:11,720
A hybrid architecture is what you get when you treat Python like a service and a
400
00:16:11,720 –> 00:16:15,400
zure like the enforcement layer and power platform like the coordinator that never stops
401
00:16:15,400 –> 00:16:16,960
being a control plane.
402
00:16:16,960 –> 00:16:18,720
That’s the replacement pattern.
403
00:16:18,720 –> 00:16:22,080
And to do it, you start with the thing everyone tries to postpone.
404
00:16:22,080 –> 00:16:23,360
Identity.
405
00:16:23,360 –> 00:16:26,960
Integration paths, two directions, one governance standard.
406
00:16:26,960 –> 00:16:31,040
There are only two integration directions that matter and both are legitimate.
407
00:16:31,040 –> 00:16:33,680
Power automate to Python and Python to power automate.
408
00:16:33,680 –> 00:16:37,320
The problem is that most tenants implement both as if they’re different species with different
409
00:16:37,320 –> 00:16:38,440
standards.
410
00:16:38,440 –> 00:16:41,080
One is treated as a flow calling an API.
411
00:16:41,080 –> 00:16:44,120
The other is treated as a script calling a web hook.
412
00:16:44,120 –> 00:16:47,200
And governance evaporates because it’s just automation.
413
00:16:47,200 –> 00:16:48,200
It’s not.
414
00:16:48,200 –> 00:16:52,080
It’s crossed here execution and it needs one governance standard, no matter which direction
415
00:16:52,080 –> 00:16:54,920
the arrow points start with power automate to Python.
416
00:16:54,920 –> 00:16:59,520
This is the cleaner mental model for most organizations because it preserves what power
417
00:16:59,520 –> 00:17:01,000
platform is good at.
418
00:17:01,000 –> 00:17:02,320
It stays the coordinator.
419
00:17:02,320 –> 00:17:03,640
A trigger happens.
420
00:17:03,640 –> 00:17:07,160
A maker owned process decides that computation is required.
421
00:17:07,160 –> 00:17:10,880
Then the flow calls a deterministic execution service and waits for a result.
422
00:17:10,880 –> 00:17:14,960
The flow remains the system of record for the process state approvals notifications and
423
00:17:14,960 –> 00:17:15,960
escalation.
424
00:17:15,960 –> 00:17:18,880
Python does the heavy lifting and returns structured output.
425
00:17:18,880 –> 00:17:23,080
That output has to look like a contract, a schema, a status, a list of errors, a data and
426
00:17:23,080 –> 00:17:24,080
a correlation ID.
427
00:17:24,080 –> 00:17:26,400
Not here’s a string, not check the logs.
428
00:17:26,400 –> 00:17:28,000
Not it worked on my machine.
429
00:17:28,000 –> 00:17:32,640
If the execution tier fails, the orchestration tier should be able to route that failure.
430
00:17:32,640 –> 00:17:36,720
Retry intentionally, raise an incident or park the record for human review.
431
00:17:36,720 –> 00:17:40,760
That means the flow needs stable responses and stable failure modes.
432
00:17:40,760 –> 00:17:42,760
The execution tier’s job is not to be clever.
433
00:17:42,760 –> 00:17:43,920
It’s to be predictable.
434
00:17:43,920 –> 00:17:44,920
Now flip it.
435
00:17:44,920 –> 00:17:46,400
Python to power automate.
436
00:17:46,400 –> 00:17:48,320
This direction exists for a reason.
437
00:17:48,320 –> 00:17:50,400
Sometimes the event source isn’t power platform.
438
00:17:50,400 –> 00:17:51,400
It’s a data science job.
439
00:17:51,400 –> 00:17:52,400
It’s a batch ingestion.
440
00:17:52,400 –> 00:17:53,520
It’s an external system.
441
00:17:53,520 –> 00:17:57,160
It’s a scheduled compute process that decides something important happened and the business
442
00:17:57,160 –> 00:18:02,680
process needs to run, notify a team, create an approval, update a dataverse record through
443
00:18:02,680 –> 00:18:05,960
a governed path or kickoff downstream coordination.
444
00:18:05,960 –> 00:18:09,120
So Python calls a flow, usually through an HTTP trigger.
445
00:18:09,120 –> 00:18:13,000
And this is where people get sloppy because HTTP triggers look like convenience.
446
00:18:13,000 –> 00:18:14,000
They’re not.
447
00:18:14,000 –> 00:18:15,400
They are an orchestration entry point.
448
00:18:15,400 –> 00:18:17,920
They are literally the front door to your control plane.
449
00:18:17,920 –> 00:18:21,520
Treating them like a back door is how you end up with anonymous URLs floating around
450
00:18:21,520 –> 00:18:26,240
in scripts, paste it into wikis, shared in email threads, and embedded in code that gets
451
00:18:26,240 –> 00:18:28,240
copied into the next quick fix.
452
00:18:28,240 –> 00:18:29,320
You can’t rotate culture.
453
00:18:29,320 –> 00:18:30,520
You can rotate credentials.
454
00:18:30,520 –> 00:18:36,000
So if Python triggers power automate, it must do it as an authenticated, authorized principle
455
00:18:36,000 –> 00:18:40,120
with explicit permissions and the flow must enforce those assumptions.
456
00:18:40,120 –> 00:18:43,240
The caller identity shouldn’t be anyone who knows the URL.
457
00:18:43,240 –> 00:18:46,360
It should be a workload identity you can disable scope and audit.
458
00:18:46,360 –> 00:18:50,520
By directionality matters because it decouples business coordination from compute.
459
00:18:50,520 –> 00:18:52,680
That’s the entire point of the three tier model.
460
00:18:52,680 –> 00:18:57,240
You want the workflow to remain stable even as the execution logic evolves and you want
461
00:18:57,240 –> 00:19:01,200
execution to scale and change without rewriting the business process layer.
462
00:19:01,200 –> 00:19:03,240
Both directions support that decoupling.
463
00:19:03,240 –> 00:19:05,600
But only if they share one governance standard.
464
00:19:05,600 –> 00:19:07,840
There is that standard and it’s non-negotiable.
465
00:19:07,840 –> 00:19:11,720
Every cross tier call must be authenticated, authorized, and logged.
466
00:19:11,720 –> 00:19:15,640
Authenticated means the caller proves who it is using tokens not shared secrets stuffed
467
00:19:15,640 –> 00:19:17,160
into a flow action.
468
00:19:17,160 –> 00:19:21,160
Authorized means the caller can only do the specific thing it needs to do, not contributor
469
00:19:21,160 –> 00:19:24,360
on the whole resource group because it was faster.
470
00:19:24,360 –> 00:19:28,440
Logged means the call creates evidence who called what was requested, what was returned,
471
00:19:28,440 –> 00:19:30,280
how long it took, and why it failed.
472
00:19:30,280 –> 00:19:33,200
And yes, the log requirement is part of the interface.
473
00:19:33,200 –> 00:19:37,640
If you can’t correlate the flow run to the function invocation to the downstream data
474
00:19:37,640 –> 00:19:40,160
verse operation, you do not have an architecture.
475
00:19:40,160 –> 00:19:41,720
You have a distributed guessing game.
476
00:19:41,720 –> 00:19:45,920
This is also where people start arguing about tools, functions versus containers.
477
00:19:45,920 –> 00:19:48,440
APIM versus direct calls.
478
00:19:48,440 –> 00:19:50,800
Private endpoints versus public with IP restrictions.
479
00:19:50,800 –> 00:19:52,280
Those details matter later.
480
00:19:52,280 –> 00:19:53,960
First you decide the behavioral rules.
481
00:19:53,960 –> 00:19:57,120
The hybrid mandate doesn’t care whether you like Python or dislike it.
482
00:19:57,120 –> 00:20:00,480
It cares whether the execution tier behaves like a govern service.
483
00:20:00,480 –> 00:20:03,960
It cares whether the orchestration tier remains readable and survivable.
484
00:20:03,960 –> 00:20:06,920
It cares whether Azure enforces the boundaries you claim exist.
485
00:20:06,920 –> 00:20:09,480
So pick your direction based on the event source.
486
00:20:09,480 –> 00:20:13,800
But enforce the same governance standard either way and start where every boundary decision
487
00:20:13,800 –> 00:20:16,560
starts, whether you admitted or not, identity.
488
00:20:16,560 –> 00:20:19,880
Identity boundary, flow authenticated via intra ID.
489
00:20:19,880 –> 00:20:24,000
Identity is where hybrid architectures either become governable or become folklore.
490
00:20:24,000 –> 00:20:27,640
Because the first thing most people do when they connect, power automate to some Python
491
00:20:27,640 –> 00:20:28,720
is borrow a human.
492
00:20:28,720 –> 00:20:32,040
They create a connection with their own account, test it, publish it and move on.
493
00:20:32,040 –> 00:20:33,440
It runs, the business is happy.
494
00:20:33,440 –> 00:20:38,160
And now production depends on one person’s token refresh behavior, licensing status, MFA
495
00:20:38,160 –> 00:20:40,800
prompts, password resets and eventual offboarding.
496
00:20:40,800 –> 00:20:42,160
That isn’t automation.
497
00:20:42,160 –> 00:20:44,240
That’s employee impersonation at scale.
498
00:20:44,240 –> 00:20:48,640
In the hybrid mandate, every cross tier call is a workload call, not a human call.
499
00:20:48,640 –> 00:20:53,720
That means the principle has to be explicit, named, owned, auditable.
500
00:20:53,720 –> 00:20:57,880
And designed to survive leadership changes, reogs and attrition.
501
00:20:57,880 –> 00:21:00,520
Because those are the only constants in enterprise IT.
502
00:21:00,520 –> 00:21:02,000
So start with the hard rule.
503
00:21:02,000 –> 00:21:06,480
Stop using some users credentials for anything that runs without a user present.
504
00:21:06,480 –> 00:21:10,320
If a flow needs to call the Python execution tier, typically an Azure function, container
505
00:21:10,320 –> 00:21:15,120
endpoint or a service behind API management, then the flow must authenticate using intra
506
00:21:15,120 –> 00:21:17,280
ID as a workload identity.
507
00:21:17,280 –> 00:21:21,960
In practice, that usually means one of two things, a service principle or a managed identity.
508
00:21:21,960 –> 00:21:24,160
A service principle is the classic pattern.
509
00:21:24,160 –> 00:21:29,040
An app registration in intra ID with defined permissions, a credential and a clear life cycle.
510
00:21:29,040 –> 00:21:30,040
It’s fine.
511
00:21:30,040 –> 00:21:34,000
It’s also where entropy enters because people treat client secrets like passwords and
512
00:21:34,000 –> 00:21:36,080
then paste them into places they don’t belong.
513
00:21:36,080 –> 00:21:40,920
A secret in a flow action, a secret in an environment variable that’s shared across environments,
514
00:21:40,920 –> 00:21:44,000
a secret in a wiki page because the SOE needs it.
515
00:21:44,000 –> 00:21:48,080
Then six months later, nobody knows where it’s used, so nobody rotates it.
516
00:21:48,080 –> 00:21:50,720
Now the secret is permanent and permanent secrets are a design failure.
517
00:21:50,720 –> 00:21:55,040
A managed identity is what enterprises should prefer when the execution tier lives in a
518
00:21:55,040 –> 00:21:56,040
Azure.
519
00:21:56,040 –> 00:21:57,960
It removes the secret handling problem entirely.
520
00:21:57,960 –> 00:21:59,520
The runtime gets an identity.
521
00:21:59,520 –> 00:22:01,680
The identity gets permissions.
522
00:22:01,680 –> 00:22:03,240
Tokens are issued automatically.
523
00:22:03,240 –> 00:22:04,640
Rotation is no longer your problem.
524
00:22:04,640 –> 00:22:05,880
That’s not convenience.
525
00:22:05,880 –> 00:22:09,880
That’s reducing attack surface and operational toilet at the same time, which is rare enough
526
00:22:09,880 –> 00:22:12,360
that you should take it whenever you can.
527
00:22:12,360 –> 00:22:15,720
But whether you use a service principle or manage the identity, the critical behavior
528
00:22:15,720 –> 00:22:16,720
is the same.
529
00:22:16,720 –> 00:22:19,040
Token-based calls with least privilege.
530
00:22:19,040 –> 00:22:22,680
The execution tier should accept only valid tokens from known callers.
531
00:22:22,680 –> 00:22:25,040
It should validate audience issuer and claims.
532
00:22:25,040 –> 00:22:29,480
It should reject anonymous calls, shared keys and its internal assumptions.
533
00:22:29,480 –> 00:22:33,000
And the identity should be scoped to exactly what it needs.
534
00:22:33,000 –> 00:22:36,280
Call this API in this environment with this role.
535
00:22:36,280 –> 00:22:38,480
Not contributor because it was faster.
536
00:22:38,480 –> 00:22:40,600
Not owner because troubleshooting was annoying.
537
00:22:40,600 –> 00:22:42,640
Those shortcuts don’t stay temporary.
538
00:22:42,640 –> 00:22:44,000
They become the architecture.
539
00:22:44,000 –> 00:22:48,320
This is also where conditional access enters the chat and quietly ruins people’s day.
540
00:22:48,320 –> 00:22:50,920
Non-interactive workloads don’t do MFA prompts.
541
00:22:50,920 –> 00:22:52,880
They don’t pass device compliance checks.
542
00:22:52,880 –> 00:22:54,120
They don’t open a browser.
543
00:22:54,120 –> 00:22:58,080
So the tenant needs conditional access policies that explicitly account for service principles
544
00:22:58,080 –> 00:22:59,640
and managed identities.
545
00:22:59,640 –> 00:23:02,240
Otherwise you’ll oscillate between two failure modes.
546
00:23:02,240 –> 00:23:06,520
Either you block the workload and break production, or you exempt it broadly and create a permanent
547
00:23:06,520 –> 00:23:07,520
bypass.
548
00:23:07,520 –> 00:23:09,240
The hybrid mandate doesn’t accept either.
549
00:23:09,240 –> 00:23:13,520
The identity boundary must be designed as a first class workload pattern.
550
00:23:13,520 –> 00:23:17,880
Dedicated principles, explicit assignments and policies that treat automation as automation
551
00:23:17,880 –> 00:23:20,280
not as a human pretending to be a robot.
552
00:23:20,280 –> 00:23:21,960
Now the ownership model.
553
00:23:21,960 –> 00:23:25,400
This is the part everyone avoids because it forces accountability.
554
00:23:25,400 –> 00:23:26,880
Who owns the app registration?
555
00:23:26,880 –> 00:23:28,360
Who owns the managed identity?
556
00:23:28,360 –> 00:23:29,880
Who owns the API permissions?
557
00:23:29,880 –> 00:23:33,200
Who owns incident response when the principle starts getting denied?
558
00:23:33,200 –> 00:23:35,760
If the answer is the maker, you’ve already lost.
559
00:23:35,760 –> 00:23:38,080
Because makers don’t own entrapostia.
560
00:23:38,080 –> 00:23:39,480
Security and platform teams do.
561
00:23:39,480 –> 00:23:43,920
If the answer is the cloud team but they don’t own the flow logic, you’ve split responsibility
562
00:23:43,920 –> 00:23:44,920
without a contract.
563
00:23:44,920 –> 00:23:46,440
So define it.
564
00:23:46,440 –> 00:23:52,440
makers own orchestration artifacts, engineers own execution services and platform security
565
00:23:52,440 –> 00:23:54,040
owns identities and policy.
566
00:23:54,040 –> 00:23:55,600
And yes, that sounds bureaucratic.
567
00:23:55,600 –> 00:23:56,600
It’s not.
568
00:23:56,600 –> 00:23:58,080
It’s survivability engineering.
569
00:23:58,080 –> 00:24:02,400
Because when an employee leaves, a flow authenticated as them becomes an outage with a calendar
570
00:24:02,400 –> 00:24:03,400
invite.
571
00:24:03,400 –> 00:24:07,240
When a flow authenticates as a workload principle, off-boarding is irrelevant.
572
00:24:07,240 –> 00:24:11,240
The system keeps running and the audit trail still points to a non-human identity that
573
00:24:11,240 –> 00:24:16,040
can be governed, rotated and revoked, without rewriting the business process.
574
00:24:16,040 –> 00:24:19,440
This is why identity is the first boundary it determines every other boundary.
575
00:24:19,440 –> 00:24:22,640
But identity without network containment is still an exposed surface.
576
00:24:22,640 –> 00:24:28,480
So next comes the network boundary where private stops being a vibe and becomes a property.
577
00:24:28,480 –> 00:24:31,120
Network boundary, private endpoint for the function.
578
00:24:31,120 –> 00:24:33,040
Network is the part everyone hand waves with.
579
00:24:33,040 –> 00:24:34,760
It’s in Azure, so it’s fine.
580
00:24:34,760 –> 00:24:38,960
That sentence has funded more incident retrospectives than any attacker ever has.
581
00:24:38,960 –> 00:24:44,320
If the Python execution tier sits behind a public URL, you’ve created a permanent exception.
582
00:24:44,320 –> 00:24:47,720
Maybe you lock it down with a function key, maybe you add IP restrictions, maybe you stick
583
00:24:47,720 –> 00:24:50,200
it behind a waft later, but the physics don’t change.
584
00:24:50,200 –> 00:24:53,960
You made your execution tier internet reachable and now you will spend the rest of its life
585
00:24:53,960 –> 00:24:55,960
explaining why that’s acceptable.
586
00:24:55,960 –> 00:24:57,520
This is the uncomfortable truth.
587
00:24:57,520 –> 00:24:59,720
Public endpoints become policy debt.
588
00:24:59,720 –> 00:25:04,000
They start as temporary, then they become dependency, then they become sacred.
589
00:25:04,000 –> 00:25:06,440
Once flows, scripts and systems depend on that endpoint.
590
00:25:06,440 –> 00:25:09,200
Nobody wants to break it to fix it, so it stays public.
591
00:25:09,200 –> 00:25:13,600
Forever, with just one allow list, with just one bypass for a partner, with just one
592
00:25:13,600 –> 00:25:15,280
exception for a test tool.
593
00:25:15,280 –> 00:25:18,880
And then your back to conditional chaos, except now it’s network shaped.
594
00:25:18,880 –> 00:25:21,320
Private endpoint exists to stop the argument.
595
00:25:21,320 –> 00:25:23,960
Private endpoint makes reachable a govern property.
596
00:25:23,960 –> 00:25:25,760
The service is still the same function app.
597
00:25:25,760 –> 00:25:29,560
The code is still the same Python, but the front door moves off the public internet and
598
00:25:29,560 –> 00:25:31,520
into your private address space.
599
00:25:31,520 –> 00:25:36,840
That means if something wants to call the execution tier, it has to be inside your network boundary,
600
00:25:36,840 –> 00:25:39,960
or it has to come through an explicitly governed ingress point.
601
00:25:39,960 –> 00:25:44,080
That distinction matters because identity without containment is still an attack surface.
602
00:25:44,080 –> 00:25:46,080
Entra proves who is calling?
603
00:25:46,080 –> 00:25:47,160
Network proves from where?
604
00:25:47,160 –> 00:25:51,200
If you only do identity, you’re still betting that nobody can reach the endpoint except
605
00:25:51,200 –> 00:25:52,480
the callers you intended.
606
00:25:52,480 –> 00:25:54,280
That’s not an architectural guarantee.
607
00:25:54,280 –> 00:25:55,640
That’s a hope with certificates.
608
00:25:55,640 –> 00:25:57,800
So what does this look like in a hybrid mandate?
609
00:25:57,800 –> 00:26:00,680
The Python execution tier runs in Azure Functions.
610
00:26:00,680 –> 00:26:03,480
The function gets vnet integration for outbound.
611
00:26:03,480 –> 00:26:07,240
Then you expose inbound through private endpoint, so the function’s runtime is reachable
612
00:26:07,240 –> 00:26:10,360
only via private IP with private DNS resolution.
613
00:26:10,360 –> 00:26:13,520
Now your API isn’t on the internet with rules.
614
00:26:13,520 –> 00:26:17,800
It’s an internal service with an explicit entry path, and yes, there are multiple patterns
615
00:26:17,800 –> 00:26:21,200
depending on how strict you need to be and what else you’re integrating with.
616
00:26:21,200 –> 00:26:22,440
The details change.
617
00:26:22,440 –> 00:26:23,520
The principle doesn’t.
618
00:26:23,520 –> 00:26:27,720
You don’t make your execution tier public just because it’s convenient for a flow action.
619
00:26:27,720 –> 00:26:31,080
There’s an immediate pushback here, but power automate is SAS.
620
00:26:31,080 –> 00:26:32,960
How does it call a private endpoint?
621
00:26:32,960 –> 00:26:36,600
That question is exactly why network boundaries force architectural clarity.
622
00:26:36,600 –> 00:26:41,160
If a SAS orchestrator has to call into a private execution tier, you need a deliberate bridge.
623
00:26:41,160 –> 00:26:44,040
Not a leak, not a random public exception.
624
00:26:44,040 –> 00:26:47,480
Sometimes that bridge is API management with private back end connectivity acting as
625
00:26:47,480 –> 00:26:49,960
a controlled ingress with policy enforcement.
626
00:26:49,960 –> 00:26:52,360
Sometimes it’s a relay pattern, sometimes it’s a queue.
627
00:26:52,360 –> 00:26:56,520
The flow writes a message to a governed broker, and the execution tier pulls it from inside
628
00:26:56,520 –> 00:26:57,520
the network.
629
00:26:57,520 –> 00:27:00,520
The hybrid mandate doesn’t require one specific implementation.
630
00:27:00,520 –> 00:27:05,440
It requires that the bridge is explicit, auditable and owned because the failure mode is predictable.
631
00:27:05,440 –> 00:27:10,080
If the flow can’t reach the function privately, people will make it public for now.
632
00:27:10,080 –> 00:27:12,280
And for now is how permanent exposure happens.
633
00:27:12,280 –> 00:27:15,520
Private endpoint also forces you to get serious about outbound paths.
634
00:27:15,520 –> 00:27:18,800
A function app can talk to anything by default if you let it.
635
00:27:18,800 –> 00:27:22,880
That means the execution tier can quietly become a data exfiltration engine with legitimate
636
00:27:22,880 –> 00:27:24,120
credentials.
637
00:27:24,120 –> 00:27:28,960
Private networking and controlled egress through naty, firewalls or inspected routes turn
638
00:27:28,960 –> 00:27:34,160
outbound traffic into something you can actually reason about, not perfectly, but architecturally.
639
00:27:34,160 –> 00:27:36,160
And when you do that, you change the operating model.
640
00:27:36,160 –> 00:27:40,320
You stop treating the execution tier like a hobby project and start treating it like production
641
00:27:40,320 –> 00:27:45,560
infrastructure, governed ingress, governed egress, named dependencies, and no surprise internet
642
00:27:45,560 –> 00:27:47,240
reachability.
643
00:27:47,240 –> 00:27:49,840
The business benefit isn’t security theater.
644
00:27:49,840 –> 00:27:50,840
It’s stability.
645
00:27:50,840 –> 00:27:54,160
When an endpoint is private, random internet noise doesn’t hit it.
646
00:27:54,160 –> 00:27:55,760
Scanners don’t find it.
647
00:27:55,760 –> 00:27:58,040
Opportunistic probing doesn’t become your baseline.
648
00:27:58,040 –> 00:28:02,080
You reduce the ambient attack traffic that everyone pretends doesn’t matter until it does.
649
00:28:02,080 –> 00:28:03,760
So the network boundary is simple.
650
00:28:03,760 –> 00:28:06,680
The Python execution tier lives behind private endpoint.
651
00:28:06,680 –> 00:28:10,920
If something needs to reach it, it does so through a designed path, not a public exception.
652
00:28:10,920 –> 00:28:13,760
And once you accept that, the next boundary becomes obvious.
653
00:28:13,760 –> 00:28:17,080
Network controls are pointless if the data path is still unmanaged.
654
00:28:17,080 –> 00:28:18,880
So now you define the data boundary.
655
00:28:18,880 –> 00:28:22,560
Dataverse stays inside the platform and you stop pretending direct external access is
656
00:28:22,560 –> 00:28:24,440
just integration.
657
00:28:24,440 –> 00:28:25,440
Data boundary.
658
00:28:25,440 –> 00:28:28,280
Dataverse never directly exposed externally.
659
00:28:28,280 –> 00:28:32,520
Dataverse is where organizations accidentally confuse accessible with governed.
660
00:28:32,520 –> 00:28:36,800
Because dataverse feels like a database, it has tables, rows, relationships, and an API
661
00:28:36,800 –> 00:28:37,800
surface.
662
00:28:37,800 –> 00:28:39,120
So the instinct is obvious.
663
00:28:39,120 –> 00:28:42,640
If Python needs data, just let Python talk to dataverse directly.
664
00:28:42,640 –> 00:28:44,840
Over the API, get the job done.
665
00:28:44,840 –> 00:28:47,560
That instinct is how the data boundary collapses.
666
00:28:47,560 –> 00:28:51,680
In the hybrid mandate, dataverse is the governed system of record that stays behind
667
00:28:51,680 –> 00:28:52,680
the platform.
668
00:28:52,680 –> 00:28:56,080
It is not an integration playground for every script that wants a shortcut.
669
00:28:56,080 –> 00:28:57,280
The reason isn’t moral.
670
00:28:57,280 –> 00:28:58,280
It’s mechanical.
671
00:28:58,280 –> 00:29:02,440
The moment you expose dataverse directly to external execution runtimes, you multiply
672
00:29:02,440 –> 00:29:07,200
the number of identities, endpoints, and permission models that can touch your core business data.
673
00:29:07,200 –> 00:29:08,520
You’re not integrating.
674
00:29:08,520 –> 00:29:10,320
You’re expanding the blast radius.
675
00:29:10,320 –> 00:29:14,280
And blast radius is what audits actually measure even when they pretend they’re asking
676
00:29:14,280 –> 00:29:15,280
about policies.
677
00:29:15,280 –> 00:29:16,400
So the rule is simple.
678
00:29:16,400 –> 00:29:20,680
The execution tier talks to a controlled interface, not to dataverse endpoints.
679
00:29:20,680 –> 00:29:23,440
Power platform orchestrates access to dataverse.
680
00:29:23,440 –> 00:29:26,400
And as your governs the interface that crosses tiers.
681
00:29:26,400 –> 00:29:30,520
That means the Python tier should not be running an SDK that casually reads whole tables
682
00:29:30,520 –> 00:29:31,520
because it can.
683
00:29:31,520 –> 00:29:35,240
It should be calling a service contract that gives it only the minimum payload needed to
684
00:29:35,240 –> 00:29:36,240
compute.
685
00:29:36,240 –> 00:29:40,440
If the execution tier needs 12 fields, it gets 12 fields, not the record, not the table,
686
00:29:40,440 –> 00:29:42,800
not a just in case dump because it was convenient.
687
00:29:42,800 –> 00:29:43,800
This might seem restrictive.
688
00:29:43,800 –> 00:29:44,800
It’s not.
689
00:29:44,800 –> 00:29:48,640
It’s what keeps your tenant from turning into an accidental data lake full of copies, caches,
690
00:29:48,640 –> 00:29:50,280
and half deleted exports.
691
00:29:50,280 –> 00:29:52,000
Think in terms of the authorization graph.
692
00:29:52,000 –> 00:29:56,280
When a flow reads dataverse, it does so through a governed identity and an environment
693
00:29:56,280 –> 00:29:58,680
boundary that your platform team can see.
694
00:29:58,680 –> 00:30:02,760
When a random script reads dataverse, you’ve shifted access into places you don’t inventory
695
00:30:02,760 –> 00:30:08,280
well, developer machines, notebooks, build agents, containers, and service principles that
696
00:30:08,280 –> 00:30:11,560
end up overprivileged because it kept failing.
697
00:30:11,560 –> 00:30:13,200
That is the erosion path.
698
00:30:13,200 –> 00:30:14,520
Complexity creates friction.
699
00:30:14,520 –> 00:30:17,800
Friction creates privilege escalation and privilege escalation becomes permanent.
700
00:30:17,800 –> 00:30:19,760
The clean pattern is mediated access.
701
00:30:19,760 –> 00:30:23,760
Power automate or a governed API tier reads from dataverse and sends a narrow payload to
702
00:30:23,760 –> 00:30:25,400
Python for execution.
703
00:30:25,400 –> 00:30:29,400
Then returns a narrow result, normalized data, validation outcomes, dedupe decisions,
704
00:30:29,400 –> 00:30:33,000
inference scores, whatever the use case requires, then the orchestration tier commits back to
705
00:30:33,000 –> 00:30:35,200
dataverse through its governed pathways.
706
00:30:35,200 –> 00:30:36,520
This is not about performance.
707
00:30:36,520 –> 00:30:39,600
It’s about control because commit is where damage happens.
708
00:30:39,600 –> 00:30:44,360
Reads can leak, rights can corrupt, so the architecture has to make rights boring, predictable
709
00:30:44,360 –> 00:30:45,720
and policy bound.
710
00:30:45,720 –> 00:30:50,600
Dataverse rights should happen through patterns you can audit, throttle, and correlate.
711
00:30:50,600 –> 00:30:53,280
Not through scripts that mostly follow the rules.
712
00:30:53,280 –> 00:30:57,480
The other part of the data boundary is DLP alignment, and this is where most organizations
713
00:30:57,480 –> 00:31:00,160
get exposed while thinking they’re protected.
714
00:31:00,160 –> 00:31:03,400
DLP policies and power platform can restrict connector pairings.
715
00:31:03,400 –> 00:31:07,160
They can prevent dataverse data from flowing into consumer connectors.
716
00:31:07,160 –> 00:31:11,520
But if you let Python pull data directly from dataverse, then DLP becomes irrelevant.
717
00:31:11,520 –> 00:31:15,160
The data has already crossed the boundary into an uncontrolled runtime.
718
00:31:15,160 –> 00:31:16,560
From there it can go anywhere.
719
00:31:16,560 –> 00:31:21,000
Files, outbound APIs, third-party libraries, random storage accounts, or temporary folders
720
00:31:21,000 –> 00:31:22,960
that somehow last for years.
721
00:31:22,960 –> 00:31:26,480
So if you care about DLP, you have to care about where the data exits.
722
00:31:26,480 –> 00:31:30,160
The execution tier must receive only what it needs, and it must operate inside the same
723
00:31:30,160 –> 00:31:33,680
governance story, identity, network containment, and logged egress.
724
00:31:33,680 –> 00:31:37,400
Otherwise DLP is theater applied after the data already left.
725
00:31:37,400 –> 00:31:41,800
And yes, there are legitimate cases where pro developers will say, “But the dataverse SDK
726
00:31:41,800 –> 00:31:43,320
for Python exists.”
727
00:31:43,320 –> 00:31:46,520
Or, “We can use service to service authentication.”
728
00:31:46,520 –> 00:31:48,920
Or “We can lock it down with least privilege.”
729
00:31:48,920 –> 00:31:49,920
Those are tools.
730
00:31:49,920 –> 00:31:50,920
They are not a boundary.
731
00:31:50,920 –> 00:31:55,000
Then architectural rule that survives staff turnover, project pressure, and the next urgent
732
00:31:55,000 –> 00:31:56,000
request.
733
00:31:56,000 –> 00:31:59,320
If your boundary depends on every engineer remembering to do least privilege perfectly,
734
00:31:59,320 –> 00:32:00,320
you don’t have a boundary.
735
00:32:00,320 –> 00:32:01,400
You have good intentions.
736
00:32:01,400 –> 00:32:04,640
The hybrid mandate treats dataverse like a protected core.
737
00:32:04,640 –> 00:32:06,840
It stays inside the power platform trust envelope.
738
00:32:06,840 –> 00:32:10,780
Everything outside talks to it through explicit contracts that you can version, validate,
739
00:32:10,780 –> 00:32:11,780
and monitor.
740
00:32:11,780 –> 00:32:15,480
That reduces the number of paths into your system of record, and it keeps your data movement
741
00:32:15,480 –> 00:32:17,920
explainable when the inevitable question arrives.
742
00:32:17,920 –> 00:32:19,320
Where does this data go?
743
00:32:19,320 –> 00:32:22,800
So the data boundary is the line that keeps your system coherent.
744
00:32:22,800 –> 00:32:26,000
Dataverse never becomes a public dependency of the execution tier.
745
00:32:26,000 –> 00:32:28,560
Once you accept that the next boundary becomes unavoidable.
746
00:32:28,560 –> 00:32:32,680
If Python talks to a controlled interface, then that interface has to be managed as an
747
00:32:32,680 –> 00:32:35,240
API, not as an ad hoc endpoint.
748
00:32:35,240 –> 00:32:37,400
And that’s where the API boundary enters.
749
00:32:37,400 –> 00:32:40,960
The function gets wrapped in API management, whether you like it or not.
750
00:32:40,960 –> 00:32:45,000
API, boundary, function wrapped in API management.
751
00:32:45,000 –> 00:32:49,120
Once dataverse stops being directly reachable, you need an interface that can carry the
752
00:32:49,120 –> 00:32:50,680
load of that decision.
753
00:32:50,680 –> 00:32:53,840
And this is where most hybrid designs quietly collapse.
754
00:32:53,840 –> 00:32:58,600
They treat the Azure function like an API product, but they operate it like a shared script.
755
00:32:58,600 –> 00:33:02,880
API management exists to stop that drift, not because APM is magical, it isn’t.
756
00:33:02,880 –> 00:33:07,520
It’s because enterprises need a place where policy becomes enforceable, consistently, across
757
00:33:07,520 –> 00:33:08,640
every caller.
758
00:33:08,640 –> 00:33:13,600
If you let every flow call the function endpoint directly, you get the same outcome you always
759
00:33:13,600 –> 00:33:15,400
get in power platform.
760
00:33:15,400 –> 00:33:17,360
Hundreds of slightly different clients.
761
00:33:17,360 –> 00:33:22,160
Each with their own expectations, timeouts, payload quirks and retry behaviors.
762
00:33:22,160 –> 00:33:25,240
And then your service isn’t a service, it’s a compatibility hostage.
763
00:33:25,240 –> 00:33:27,120
APM is the contract boundary.
764
00:33:27,120 –> 00:33:30,160
It’s where the execution tier becomes an actual product.
765
00:33:30,160 –> 00:33:34,200
Versioned endpoints, documented schemers, predictable arrow shapes and policies that don’t depend
766
00:33:34,200 –> 00:33:36,240
on every maker remembering the rules.
767
00:33:36,240 –> 00:33:39,880
It’s also where you centralize throttling and abuse control, so the orchestration tier
768
00:33:39,880 –> 00:33:45,000
can scale without deducing your own back end by accident, because that happens.
769
00:33:45,000 –> 00:33:49,000
Your automated retries are not polite, parallel branches are not polite, applied to each with
770
00:33:49,000 –> 00:33:51,160
concurrency turned on is definitely not polite.
771
00:33:51,160 –> 00:33:54,840
So if you don’t have a choke point, your execution tier will get load patterns that feel
772
00:33:54,840 –> 00:33:59,320
like an attack, except they’re coming from your own tenant with legitimate permissions.
773
00:33:59,320 –> 00:34:01,600
APM gives you a place to enforce.
774
00:34:01,600 –> 00:34:07,640
Rate limits, quotas, header requirements, payload size and response timeouts, not as guidance
775
00:34:07,640 –> 00:34:08,800
as reality.
776
00:34:08,800 –> 00:34:11,800
It also gives you a place to enforce authentication consistently.
777
00:34:11,800 –> 00:34:15,960
You already decided cross tier calls must use enter based workload identity.
778
00:34:15,960 –> 00:34:18,880
APM lets you make that the default behavior.
779
00:34:18,880 –> 00:34:23,800
Validate tokens, validate audiences, reject unknown issuers, reject missing scopes and
780
00:34:23,800 –> 00:34:26,660
do it before the request ever reaches your function runtime.
781
00:34:26,660 –> 00:34:29,240
That distinction matters because functions are execution.
782
00:34:29,240 –> 00:34:33,840
They should spend CPU doing compute, not doing gatekeeping for every caller variation.
783
00:34:33,840 –> 00:34:35,200
You forgot to constrain.
784
00:34:35,200 –> 00:34:38,760
Then there’s the part everyone ignores until the platform turns on them.
785
00:34:38,760 –> 00:34:44,240
Flows live for years, makers copy them, departments fork them, someone saves a template in a team
786
00:34:44,240 –> 00:34:46,800
and suddenly you have 50 clones calling your endpoint.
787
00:34:46,800 –> 00:34:50,600
If your function API changes shape and you don’t have a versioning story, you’ll break
788
00:34:50,600 –> 00:34:53,000
production in places you can’t even find.
789
00:34:53,000 –> 00:34:55,560
APM is where you make versioning boring.
790
00:34:55,560 –> 00:34:57,360
V1 does what it always did.
791
00:34:57,360 –> 00:34:59,400
V2 exists when you need to evolve.
792
00:34:59,400 –> 00:35:03,080
Deprecation becomes a planned life cycle event, not a surprise outage.
793
00:35:03,080 –> 00:35:07,120
And you can instrument which clients still hit V1 so you can actually drive retirement.
794
00:35:07,120 –> 00:35:09,120
That’s governance, not policy documents.
795
00:35:09,120 –> 00:35:13,840
APM also forces contract discipline which is the opposite of just past JSON.
796
00:35:13,840 –> 00:35:16,760
The execution tier should reject ambiguous payloads.
797
00:35:16,760 –> 00:35:18,640
If a field is required, it’s required.
798
00:35:18,640 –> 00:35:20,600
If a schema changed, the caller needs to know.
799
00:35:20,600 –> 00:35:22,600
If an array is too large, fail fast.
800
00:35:22,600 –> 00:35:24,160
If a content type is wrong, reject it.
801
00:35:24,160 –> 00:35:28,800
The point is to stop garbage in from becoming mysterious behavior that you debug at 3am
802
00:35:28,800 –> 00:35:31,560
power platform teams hate this at first because it feels strict.
803
00:35:31,560 –> 00:35:32,760
It’s supposed to.
804
00:35:32,760 –> 00:35:35,200
Strict contracts are what keep orchestration maintainable.
805
00:35:35,200 –> 00:35:39,400
When flows can send anything and the backend tries to guess intent, you’re back to probabilistic
806
00:35:39,400 –> 00:35:40,400
behavior.
807
00:35:40,400 –> 00:35:42,160
You’re back to exceptions being architecture.
808
00:35:42,160 –> 00:35:46,640
APM lets you enforce validation and normalization at the boundary so both sides stay honest.
809
00:35:46,640 –> 00:35:51,440
And yes, APM is also the right place for transformation policies when you absolutely need them.
810
00:35:51,440 –> 00:35:57,120
Rewrite headers, map fields, standardize error responses, even do lightweight filtering.
811
00:35:57,120 –> 00:35:58,120
The rule is simple.
812
00:35:58,120 –> 00:36:00,520
APM enforces interface behavior.
813
00:36:00,520 –> 00:36:02,720
Python executes business compute.
814
00:36:02,720 –> 00:36:05,440
It rebuilds your service logic and policies.
815
00:36:05,440 –> 00:36:07,680
That’s just moving the mess to a different UI.
816
00:36:07,680 –> 00:36:12,920
Finally, APM is how you stop every flow from becoming an API client with custom quirks.
817
00:36:12,920 –> 00:36:15,480
Without APM, makers will do what makers always do.
818
00:36:15,480 –> 00:36:21,280
Set weird timeouts, ignore error codes, pass text, and implement retry logic by adding delays.
819
00:36:21,280 –> 00:36:23,400
With APM, you can publish a single standard.
820
00:36:23,400 –> 00:36:24,400
This is the endpoint.
821
00:36:24,400 –> 00:36:25,400
This is the contract.
822
00:36:25,400 –> 00:36:26,400
This is the auth.
823
00:36:26,400 –> 00:36:27,400
This is the expected response.
824
00:36:27,400 –> 00:36:28,400
This is the error model.
825
00:36:28,400 –> 00:36:30,080
And this is the throttling behavior.
826
00:36:30,080 –> 00:36:32,520
Now your hybrid mandate looks like a system.
827
00:36:32,520 –> 00:36:33,680
It’s not a diagram.
828
00:36:33,680 –> 00:36:34,960
And this is the actual payoff.
829
00:36:34,960 –> 00:36:39,720
APM becomes the layer that lets the back and evolve while orchestration stays stable.
830
00:36:39,720 –> 00:36:44,000
Engineers can patch dependencies, optimize compute or refactor internal modules without asking
831
00:36:44,000 –> 00:36:46,560
makers to rewrite business process logic.
832
00:36:46,560 –> 00:36:47,560
The contract holds.
833
00:36:47,560 –> 00:36:49,480
The orchestration tier keeps coordinating.
834
00:36:49,480 –> 00:36:51,360
The execution tier keeps executing.
835
00:36:51,360 –> 00:36:54,680
But none of this matters if you can’t see failures across tiers.
836
00:36:54,680 –> 00:36:55,840
Governance doesn’t fail loudly.
837
00:36:55,840 –> 00:36:57,640
It fails silently.
838
00:36:57,640 –> 00:37:01,800
So the next boundary is the one that makes incident response deterministic.
839
00:37:01,800 –> 00:37:05,800
A system is a system that’s related logging across power platform, APM, and the execution
840
00:37:05,800 –> 00:37:07,520
tier.
841
00:37:07,520 –> 00:37:10,280
Logging boundary correlates logs across systems.
842
00:37:10,280 –> 00:37:14,520
Logging is where a hybrid architecture stops being a diagram and starts being debuggable.
843
00:37:14,520 –> 00:37:18,720
And most organizations fail here in the most predictable way possible.
844
00:37:18,720 –> 00:37:23,160
Every system logs its own truth in its own format with its own identifiers, and then the
845
00:37:23,160 –> 00:37:26,320
incident bridge call becomes a group project in interpretation.
846
00:37:26,320 –> 00:37:27,840
Power automate has run history.
847
00:37:27,840 –> 00:37:32,320
The PM has request logs, Azure Functions has application inside traces.
848
00:37:32,320 –> 00:37:34,560
Dataverse has audit logs and its own activity telemetry.
849
00:37:34,560 –> 00:37:36,880
They all tell a story and they just don’t tell the same story.
850
00:37:36,880 –> 00:37:39,640
So when a flow run fails, you get the comfortable lie.
851
00:37:39,640 –> 00:37:42,280
The flow failed at the HTTP action.
852
00:37:42,280 –> 00:37:43,280
That’s not a root cause.
853
00:37:43,280 –> 00:37:44,360
That’s a location marker.
854
00:37:44,360 –> 00:37:49,440
The real question is whether the request hit APM, whether APM rejected it on policy, whether
855
00:37:49,440 –> 00:37:53,360
the function code through an exception, whether the function timed out, whether the downstream
856
00:37:53,360 –> 00:37:58,200
call to dataverse was denied, and whether retries created duplicates that are now someone
857
00:37:58,200 –> 00:37:59,680
else’s problem.
858
00:37:59,680 –> 00:38:03,240
If you can’t answer those questions in minutes, you don’t have observability.
859
00:38:03,240 –> 00:38:04,640
You have distributed journaling.
860
00:38:04,640 –> 00:38:07,720
The logging boundary in the hybrid mandate is explicit.
861
00:38:07,720 –> 00:38:13,160
One correlation ID must cross the orchestration tier, the API boundary, the execution tier,
862
00:38:13,160 –> 00:38:15,040
and any governed data operations.
863
00:38:15,040 –> 00:38:19,240
The same identifier shows up everywhere, every time, no exceptions.
864
00:38:19,240 –> 00:38:22,400
Because once you have that, incident response becomes deterministic.
865
00:38:22,400 –> 00:38:27,280
You stop guessing, you stop screenshot archaeology, you stop fighting over whose logs are right.
866
00:38:27,280 –> 00:38:31,520
You query the correlation ID and you see the end-to-end path of the transaction.
867
00:38:31,520 –> 00:38:35,160
So how does this work mechanically without turning into an implementation lecture?
868
00:38:35,160 –> 00:38:36,200
Start in power automate.
869
00:38:36,200 –> 00:38:41,000
The flow generates a correlation ID at the start of the run, not at the HTTP step, not inside
870
00:38:41,000 –> 00:38:42,000
Python.
871
00:38:42,000 –> 00:38:45,920
At the first moment, the orchestration tier decides, work is happening.
872
00:38:45,920 –> 00:38:50,520
That correlation ID becomes a variable and it gets attached to every cross tier call.
873
00:38:50,520 –> 00:38:55,080
First headers, payload fields were appropriate, and any status records you write to data
874
00:38:55,080 –> 00:38:56,080
verse.
875
00:38:56,080 –> 00:38:57,560
Then APIM enforces it.
876
00:38:57,560 –> 00:39:00,840
If the correlation ID header isn’t present, reject the request.
877
00:39:00,840 –> 00:39:03,720
This is the part that feels rude until you remember what you’re buying.
878
00:39:03,720 –> 00:39:06,320
The ability to operate at scale without ambiguity.
879
00:39:06,320 –> 00:39:10,360
APM can also generate one if you want, but the stronger pattern is to let orchestration
880
00:39:10,360 –> 00:39:13,120
originated so it maps cleanly to a flow run.
881
00:39:13,120 –> 00:39:17,760
Next as Zuer functions, the function code reads the correlation ID, sets it as the operation
882
00:39:17,760 –> 00:39:22,200
ID in its telemetry context and logs every meaningful step against it.
883
00:39:22,200 –> 00:39:26,400
Validation outcomes, branch decisions, downstream calls, and exceptions.
884
00:39:26,400 –> 00:39:27,880
Not verbose debug noise.
885
00:39:27,880 –> 00:39:29,840
Evidence then, downstream data operations.
886
00:39:29,840 –> 00:39:33,400
If the function writes to data verse through a governed interface, that interface must also
887
00:39:33,400 –> 00:39:35,280
log with the same correlation ID.
888
00:39:35,280 –> 00:39:39,880
If the orchestration tier writes to data verse directly, it writes the correlation ID into
889
00:39:39,880 –> 00:39:43,440
the record or an associated tracking table so you can type business data to technical
890
00:39:43,440 –> 00:39:44,600
execution.
891
00:39:44,600 –> 00:39:47,760
Now you can answer questions that otherwise turn into weak long post mortems.
892
00:39:47,760 –> 00:39:51,400
How long did the request spend in power automate before it left the orchestration tier?
893
00:39:51,400 –> 00:39:52,400
Did APM throttle it?
894
00:39:52,400 –> 00:39:53,920
And if so, how many times?
895
00:39:53,920 –> 00:39:57,360
Did the function execute or did it fail authentication at the edge?
896
00:39:57,360 –> 00:40:01,080
Did the function time out or did it throw a handled validation error?
897
00:40:01,080 –> 00:40:04,120
Did retries occur and were they idempotent or duplicative?
898
00:40:04,120 –> 00:40:05,200
How large was the payload?
899
00:40:05,200 –> 00:40:07,880
And did it cross the thresholds that trigger platform limits?
900
00:40:07,880 –> 00:40:11,120
Did permission denials occur and which principle got denied?
901
00:40:11,120 –> 00:40:16,200
Those are the metrics that matter, latency, failures, retries, payload size, throttle events,
902
00:40:16,200 –> 00:40:17,680
and authorization denials.
903
00:40:17,680 –> 00:40:21,200
Not because dashboards are fun, but because these signals tell you where architectural erosion
904
00:40:21,200 –> 00:40:22,200
is happening.
905
00:40:22,200 –> 00:40:24,840
And yes, you should push these logs somewhere central.
906
00:40:24,840 –> 00:40:27,360
Azure monitor and application insights are fine.
907
00:40:27,360 –> 00:40:31,120
Sentinel becomes relevant once you care about threat detection and not just troubleshooting.
908
00:40:31,120 –> 00:40:33,800
The product choice matters less than the behavior.
909
00:40:33,800 –> 00:40:38,560
Centralize, correlate, retain, and make it searchable by correlation ID and principle.
910
00:40:38,560 –> 00:40:42,840
This is also where you learn the uncomfortable truth about low-code observability.
911
00:40:42,840 –> 00:40:44,720
Power automate will show you what it did.
912
00:40:44,720 –> 00:40:47,520
It will not show you what your execution tier did.
913
00:40:47,520 –> 00:40:49,200
Your execution tier will show you what it did.
914
00:40:49,200 –> 00:40:51,640
It will not show you what power automate assumed.
915
00:40:51,640 –> 00:40:54,800
Without correlation, those gaps fill with human narratives.
916
00:40:54,800 –> 00:40:56,720
With correlation, they fill with data.
917
00:40:56,720 –> 00:41:00,840
And once you have correlated logs, the rest of the hybrid mandate becomes enforceable.
918
00:41:00,840 –> 00:41:02,160
You can prove boundaries exist.
919
00:41:02,160 –> 00:41:03,880
You can prove calls or authenticated.
920
00:41:03,880 –> 00:41:05,760
You can prove data didn’t move where it shouldn’t.
921
00:41:05,760 –> 00:41:08,000
You can prove which tier failed and why.
922
00:41:08,000 –> 00:41:10,440
That’s what governance looks like when it’s real.
923
00:41:10,440 –> 00:41:12,160
Evidence, not confidence.
924
00:41:12,160 –> 00:41:17,320
Now you can finally define the workflow end to end as a system, not a collection of parts.
925
00:41:17,320 –> 00:41:22,120
Conceptual flow, event, reasoning, orchestration, execution, commit.
926
00:41:22,120 –> 00:41:27,120
Now stitch the tiers together into a single conceptual flow, not because architects love diagrams,
927
00:41:27,120 –> 00:41:31,560
because your incident response team needs a mental model that survives pressure.
928
00:41:31,560 –> 00:41:32,840
The sequence is simple.
929
00:41:32,840 –> 00:41:37,040
Event reasoning, orchestration, execution, commit, five verbs, five places where intent
930
00:41:37,040 –> 00:41:39,040
can drift if you don’t pin it down.
931
00:41:39,040 –> 00:41:40,440
Start with the event.
932
00:41:40,440 –> 00:41:43,360
The event is the moment reality changes and the system notices.
933
00:41:43,360 –> 00:41:48,400
It can be an email arriving with an attachment, a team’s message, a form submission, a
934
00:41:48,400 –> 00:41:53,120
dataverse row being created or modified, a scheduled trigger that checks for late invoices,
935
00:41:53,120 –> 00:41:55,760
expiring contracts or missing compliance attestations.
936
00:41:55,760 –> 00:41:58,800
The event source doesn’t matter what matters is that events are noisy.
937
00:41:58,800 –> 00:42:01,960
They contain malformed inputs, duplicates and human chaos.
938
00:42:01,960 –> 00:42:04,480
So the event isn’t where you do the work.
939
00:42:04,480 –> 00:42:06,600
It’s where you decide whether work should happen.
940
00:42:06,600 –> 00:42:08,320
The decision is the reasoning layer.
941
00:42:08,320 –> 00:42:09,600
Reesoning is not execution.
942
00:42:09,600 –> 00:42:11,400
Reesoning is classification and rooting.
943
00:42:11,400 –> 00:42:14,560
It answers, is this request valid enough to process?
944
00:42:14,560 –> 00:42:15,920
And who owns the outcome?
945
00:42:15,920 –> 00:42:17,000
Do we need an approval?
946
00:42:17,000 –> 00:42:18,600
Which environment does this belong in?
947
00:42:18,600 –> 00:42:20,440
What category of work is this?
948
00:42:20,440 –> 00:42:24,360
Simple automation, high-risk change or something that requires escalation?
949
00:42:24,360 –> 00:42:26,760
This is where power platform earns its keep.
950
00:42:26,760 –> 00:42:29,480
A flow can apply cheap logic fast.
951
00:42:29,480 –> 00:42:32,000
Subject line filters, sender allow lists.
952
00:42:32,000 –> 00:42:33,160
Basic field validation.
953
00:42:33,160 –> 00:42:38,240
A backup of a business owner in dataverse, rooting to an approval or branching based on process state.
954
00:42:38,240 –> 00:42:39,400
Keep it readable.
955
00:42:39,400 –> 00:42:40,720
Keep it explainable.
956
00:42:40,720 –> 00:42:44,560
When a compliance lead asks why a record went down a particular path, the answer should
957
00:42:44,560 –> 00:42:47,160
be visible without reverse engineering Python.
958
00:42:47,160 –> 00:42:51,880
Then comes orchestration, which is the part most people confuse with execution.
959
00:42:51,880 –> 00:42:53,240
Orchestration is coordination over time.
960
00:42:53,240 –> 00:42:54,440
It creates a tracking record.
961
00:42:54,440 –> 00:42:55,720
It sets a correlation ID.
962
00:42:55,720 –> 00:42:57,680
It moves a process from state A to state B.
963
00:42:57,680 –> 00:42:58,680
It informs humans.
964
00:42:58,680 –> 00:42:59,680
It waits.
965
00:42:59,680 –> 00:43:00,960
It retries intentionally.
966
00:43:00,960 –> 00:43:03,120
It escalates when the process sits too long.
967
00:43:03,120 –> 00:43:07,480
It records that something happened even if the execution tier is currently unhealthy.
968
00:43:07,480 –> 00:43:11,200
This is where you enforce that the workflow is the system of record for the process, not
969
00:43:11,200 –> 00:43:13,520
the sidecar script and not the API logs.
970
00:43:13,520 –> 00:43:17,960
If the execution tier dies, the orchestration tier should still know what it asked for, when
971
00:43:17,960 –> 00:43:19,800
it asked for it, and what it’s waiting on.
972
00:43:19,800 –> 00:43:21,960
Now you cross the tier boundary into execution.
973
00:43:21,960 –> 00:43:25,480
The execution is where Python runs, but the key is that it runs as a service call, not
974
00:43:25,480 –> 00:43:26,640
as a vibe.
975
00:43:26,640 –> 00:43:31,160
The orchestration tier sends a bounded payload with a correlation ID and a contract version.
976
00:43:31,160 –> 00:43:35,960
The execution tier validates the payload, performs deterministic compute, and returns structured
977
00:43:35,960 –> 00:43:40,680
results, success, failure type, output data, and peritom errors when it’s batch work.
978
00:43:40,680 –> 00:43:42,600
This is also where identity belongs.
979
00:43:42,600 –> 00:43:46,640
The execution tier should treat the correlation ID as a first class input, so retries don’t
980
00:43:46,640 –> 00:43:47,840
create duplicates.
981
00:43:47,840 –> 00:43:51,080
If you rerun the same request, you should get the same outcome.
982
00:43:51,080 –> 00:43:53,520
Or a clean, already processed response.
983
00:43:53,520 –> 00:43:55,920
Anything else becomes retry storms and data drift.
984
00:43:55,920 –> 00:43:57,240
Then you get to commit.
985
00:43:57,240 –> 00:44:00,120
Commit is where enterprise data changes, and it has to be boring.
986
00:44:00,120 –> 00:44:04,720
It means writes back to dataverse or other systems of record through governed endpoints,
987
00:44:04,720 –> 00:44:07,680
with strict permissions and logged outcomes.
988
00:44:07,680 –> 00:44:10,400
Commit isn’t Python writes wherever it wants.
989
00:44:10,400 –> 00:44:13,360
Commit is the system records results through known paths.
990
00:44:13,360 –> 00:44:16,960
Sometimes the orchestration tier does the commit using native connectors and environment bound
991
00:44:16,960 –> 00:44:17,960
permissions.
992
00:44:17,960 –> 00:44:20,640
Sometimes the execution tier commits through an API boundary.
993
00:44:20,640 –> 00:44:22,920
Either way, the rule stays intact.
994
00:44:22,920 –> 00:44:27,360
Rites happen through interfaces that are authenticated, authorized, and observable.
995
00:44:27,360 –> 00:44:30,560
And finally, the orchestration tier closes the loop.
996
00:44:30,560 –> 00:44:35,440
It updates status, notifies stakeholders, and stores the execution output in a form the
997
00:44:35,440 –> 00:44:36,960
business can actually consume.
998
00:44:36,960 –> 00:44:39,440
Not raw logs, not screenshots, data.
999
00:44:39,440 –> 00:44:40,520
So that’s the sequence.
1000
00:44:40,520 –> 00:44:42,600
Event decides that something might matter.
1001
00:44:42,600 –> 00:44:44,640
Reasoning decides what should happen.
1002
00:44:44,640 –> 00:44:46,320
Orchestration manages the process.
1003
00:44:46,320 –> 00:44:50,720
Execution does deterministic compute, and commit records the outcome safely.
1004
00:44:50,720 –> 00:44:53,920
If you can’t name which tier owns each verb, you don’t have a hybrid model.
1005
00:44:53,920 –> 00:44:55,280
You have cross-system guesswork.
1006
00:44:55,280 –> 00:44:58,720
Now make it tangible because abstract models don’t survive first contact with spreadsheets
1007
00:44:58,720 –> 00:45:00,480
and bulk updates.
1008
00:45:00,480 –> 00:45:04,920
Scenario one, CSV, Excel processing without flow spaghetti.
1009
00:45:04,920 –> 00:45:09,280
This is the scenario that shows up in every enterprise, regardless of how digital the strategy
1010
00:45:09,280 –> 00:45:10,280
deck looks.
1011
00:45:10,280 –> 00:45:15,280
Spreadsheets, finance lives in Excel, operations lives in CSV exports, vendor send reports that
1012
00:45:15,280 –> 00:45:18,720
are really just semi-structured guesses with a header row.
1013
00:45:18,720 –> 00:45:23,320
And somehow all of that becomes a business process with deadlines and consequences.
1014
00:45:23,320 –> 00:45:25,240
For automate can process these files.
1015
00:45:25,240 –> 00:45:27,080
Of course it can, that’s not the debate.
1016
00:45:27,080 –> 00:45:30,840
The debate is what happens after the third small tweak and the fifth edge case and the
1017
00:45:30,840 –> 00:45:32,160
tenth file format.
1018
00:45:32,160 –> 00:45:33,880
That’s basically the same.
1019
00:45:33,880 –> 00:45:35,360
This is where flows become spaghetti.
1020
00:45:35,360 –> 00:45:38,560
A maker builds a flow that triggers when a file lands in SharePoint.
1021
00:45:38,560 –> 00:45:40,040
It lists rows in a table.
1022
00:45:40,040 –> 00:45:41,040
It loops.
1023
00:45:41,040 –> 00:45:42,040
It transforms text.
1024
00:45:42,040 –> 00:45:43,040
It converts date formats.
1025
00:45:43,040 –> 00:45:45,200
It tries to handle commas inside quoted fields.
1026
00:45:45,200 –> 00:45:47,520
It tries to ignore blank rows that aren’t blank.
1027
00:45:47,520 –> 00:45:50,960
It tries to detect the total line someone left at the bottom.
1028
00:45:50,960 –> 00:45:54,840
Then it tries to build error handling inside scopes because a single bad row shouldn’t fail
1029
00:45:54,840 –> 00:45:55,840
the whole run.
1030
00:45:55,840 –> 00:45:59,400
Then someone asks for a summary email with the rows that failed.
1031
00:45:59,400 –> 00:46:03,720
And now you’re building an error report generator inside an orchestration engine.
1032
00:46:03,720 –> 00:46:06,640
This is how you end up with a flow that is both fragile and expensive.
1033
00:46:06,640 –> 00:46:08,880
So in the hybrid mandate, the split is clean.
1034
00:46:08,880 –> 00:46:12,880
The flow owns intake, permission checks, status tracking and notifications.
1035
00:46:12,880 –> 00:46:15,120
It does the work that’s inherently orchestration.
1036
00:46:15,120 –> 00:46:16,520
A file arrived.
1037
00:46:16,520 –> 00:46:17,600
This is the owner.
1038
00:46:17,600 –> 00:46:19,200
This is the process state.
1039
00:46:19,200 –> 00:46:20,640
This needs approval.
1040
00:46:20,640 –> 00:46:22,280
Certify these people.
1041
00:46:22,280 –> 00:46:24,280
Record that we attempted processing.
1042
00:46:24,280 –> 00:46:26,520
Record that processing succeeded or failed.
1043
00:46:26,520 –> 00:46:31,880
The flow does not own passing, normalization, deduplication, validation, logic or report formatting.
1044
00:46:31,880 –> 00:46:33,640
Not because makers aren’t capable.
1045
00:46:33,640 –> 00:46:37,720
Because that logic needs determinism and testability and those are not native properties of a flow
1046
00:46:37,720 –> 00:46:38,720
run history.
1047
00:46:38,720 –> 00:46:43,200
So the flow receives the file, stores it in a governed location and calls the execution
1048
00:46:43,200 –> 00:46:44,200
tier.
1049
00:46:44,200 –> 00:46:47,800
The execution tier Python as a service does what Python is good at.
1050
00:46:47,800 –> 00:46:51,120
It reads the CSV or Excel with a real library built for it.
1051
00:46:51,120 –> 00:46:53,760
It normalizes columns into a defined schema.
1052
00:46:53,760 –> 00:46:55,720
It handles date passing with strict rules.
1053
00:46:55,720 –> 00:46:58,920
It detects duplicates using keys you can explain in unit test.
1054
00:46:58,920 –> 00:47:04,280
It validates every row against an explicit rule set and returns results as structured data.
1055
00:47:04,280 –> 00:47:07,880
Accepted rows, rejected rows, and why each row failed.
1056
00:47:07,880 –> 00:47:10,080
And here’s the part most organizations miss.
1057
00:47:10,080 –> 00:47:12,520
Errors come back as data, not as screenshots.
1058
00:47:12,520 –> 00:47:16,600
In the low-code only approach, a failure becomes an exception with a blob of context.
1059
00:47:16,600 –> 00:47:17,760
It’s hard to aggregate.
1060
00:47:17,760 –> 00:47:21,840
In the hybrid approach, the Python service returns a result contract that looks boring
1061
00:47:21,840 –> 00:47:26,240
on purpose, counts, row-level status, a list of validation messages with line numbers
1062
00:47:26,240 –> 00:47:29,200
or record identifiers and a correlation ID.
1063
00:47:29,200 –> 00:47:30,920
Now the flow can do what it’s actually good at.
1064
00:47:30,920 –> 00:47:32,440
It can root those errors.
1065
00:47:32,440 –> 00:47:37,560
If there are rejections, it can notify the submitter with a formatted summary and a link
1066
00:47:37,560 –> 00:47:41,400
to the rejected rows stored in a controlled table or file.
1067
00:47:41,400 –> 00:47:45,480
If the batch is clean, it can progress the process state and trigger downstream work.
1068
00:47:45,480 –> 00:47:49,760
If the batch fails validation beyond a threshold, it can escalate to a human review step.
1069
00:47:49,760 –> 00:47:54,000
And all of that remains readable in the flow because the heavy logic is not embedded in a
1070
00:47:54,000 –> 00:47:55,440
maze of expressions.
1071
00:47:55,440 –> 00:47:58,000
This is also where you stop leaking data through convenience.
1072
00:47:58,000 –> 00:48:02,960
If the execution tier is a governed service behind APIM authenticated via Entra, contained
1073
00:48:02,960 –> 00:48:07,840
by network boundaries and emitting correlated logs, then processing a spreadsheet no longer
1074
00:48:07,840 –> 00:48:11,720
means dump business data into random files and hope it’s fine.
1075
00:48:11,720 –> 00:48:14,040
It means the file enters a controlled pipeline.
1076
00:48:14,040 –> 00:48:17,160
It can take execution and commit with evidence at every step.
1077
00:48:17,160 –> 00:48:20,520
And the output contract matters more than the implementation.
1078
00:48:20,520 –> 00:48:24,360
Because once you have a stable contract, you can evolve the Python logic without rewriting
1079
00:48:24,360 –> 00:48:25,360
the business process.
1080
00:48:25,360 –> 00:48:27,080
You can add a new column mapping.
1081
00:48:27,080 –> 00:48:28,760
You can update a validation rule.
1082
00:48:28,760 –> 00:48:30,040
You can patch a dependency.
1083
00:48:30,040 –> 00:48:31,360
You can optimize performance.
1084
00:48:31,360 –> 00:48:32,520
The flow doesn’t change.
1085
00:48:32,520 –> 00:48:34,920
The process owners don’t have to relearn the automation.
1086
00:48:34,920 –> 00:48:37,320
The orchestration tier stays stable while execution improves.
1087
00:48:37,320 –> 00:48:39,160
And that’s the actual maturity move.
1088
00:48:39,160 –> 00:48:41,000
Not we used Python.
1089
00:48:41,000 –> 00:48:45,080
We separated orchestration from execution and we made the boundary explicit.
1090
00:48:45,080 –> 00:48:49,000
So the spreadsheet scenario stops being a maker right of passage and becomes a governed
1091
00:48:49,000 –> 00:48:53,080
service pattern, flow coordinates, Python computes, Azure enforces.
1092
00:48:53,080 –> 00:48:56,760
And once you’ve done it for CSV and Excel, the next failure mode becomes obvious.
1093
00:48:56,760 –> 00:48:58,000
It’s not formatting.
1094
00:48:58,000 –> 00:49:00,240
It’s scale.
1095
00:49:00,240 –> 00:49:04,560
bulk updates, throttles, partial success and the classic enterprise question.
1096
00:49:04,560 –> 00:49:08,200
Can we do 10,000 of these by tomorrow without corrupting our data?
1097
00:49:08,200 –> 00:49:12,360
Inario 2, bulk data verse updates with deterministic validation.
1098
00:49:12,360 –> 00:49:17,440
bulk updates are where power automates it worked in testing story usually ends.
1099
00:49:17,440 –> 00:49:19,360
Not because flows can’t update data verse.
1100
00:49:19,360 –> 00:49:20,360
They can.
1101
00:49:20,360 –> 00:49:24,360
The failure happens when you move from dozens of records to thousands and the platform stops
1102
00:49:24,360 –> 00:49:29,640
behaving like a friendly assistant and starts behaving like a rate limited distributed system.
1103
00:49:29,640 –> 00:49:30,640
Because that’s what it is.
1104
00:49:30,640 –> 00:49:32,720
The usual pattern is painfully consistent.
1105
00:49:32,720 –> 00:49:36,520
Someone builds a flow that queries data verse for a set of rows, then runs an apply to
1106
00:49:36,520 –> 00:49:41,400
each, then does an update a row action, maybe with concurrency turned on to speed it up and
1107
00:49:41,400 –> 00:49:45,080
then adds a couple scopes with run after conditions to catch failures.
1108
00:49:45,080 –> 00:49:46,600
It ships, it runs.
1109
00:49:46,600 –> 00:49:48,000
It even succeeds a few times.
1110
00:49:48,000 –> 00:49:53,280
Then scale shows up, throttling shows up, intermittent connector errors show up, runs timeout,
1111
00:49:53,280 –> 00:49:54,640
retries kick in.
1112
00:49:54,640 –> 00:49:58,640
Some updates succeed some fail and the flow has no coherent concept of rollback.
1113
00:49:58,640 –> 00:50:02,800
Now you have partial success with no deterministic replay strategy, which is another way of saying
1114
00:50:02,800 –> 00:50:04,880
you have data drift with a progress bar.
1115
00:50:04,880 –> 00:50:08,600
And the real damage isn’t the failures, it’s the ambiguity when someone asks which records
1116
00:50:08,600 –> 00:50:12,000
were updated, the answer turns into, well, mostly.
1117
00:50:12,000 –> 00:50:14,040
That’s not acceptable in the system of record.
1118
00:50:14,040 –> 00:50:18,720
So the hybrid mandate treats bulk updates as an execution tier problem, not an orchestration
1119
00:50:18,720 –> 00:50:19,720
tier hobby.
1120
00:50:19,720 –> 00:50:21,120
Here’s what stays in the flow.
1121
00:50:21,120 –> 00:50:25,880
In take of the request, approval if it’s a high impact change, creation of a tracking record
1122
00:50:25,880 –> 00:50:28,760
in data verse and communication to stakeholders.
1123
00:50:28,760 –> 00:50:33,760
The flow also decides the boundary conditions, which table, which segment, which job type,
1124
00:50:33,760 –> 00:50:37,320
which correlation idea and what done means, the flow owns the business meaning.
1125
00:50:37,320 –> 00:50:41,160
Then it calls Python as a service and Python does two things that flows are structurally
1126
00:50:41,160 –> 00:50:44,560
bad at, deterministic validation and deterministic batching.
1127
00:50:44,560 –> 00:50:45,840
Start with validation.
1128
00:50:45,840 –> 00:50:50,160
Before Python writes anything, it validates the entire candidate set, not one row at a time,
1129
00:50:50,160 –> 00:50:54,880
mid loop, with half the records already committed, the execution tier pulls the necessary fields
1130
00:50:54,880 –> 00:51:00,080
through a controlled interface, applies strict rules and produces a validation report.
1131
00:51:00,080 –> 00:51:03,600
Counts, categories of failure and per record reasons.
1132
00:51:03,600 –> 00:51:07,360
This is where you stop confusing update logic with data quality.
1133
00:51:07,360 –> 00:51:11,440
If you’re about to update 10,000 records, you don’t want to discover on record 7,000 Simp
1134
00:51:11,440 –> 00:51:16,280
1.32 that the data violates a rule and now you’re in the middle of a half applied change.
1135
00:51:16,280 –> 00:51:18,680
Validation first is what makes the operation reversible.
1136
00:51:18,680 –> 00:51:21,320
You can reject the whole job before it mutates reality.
1137
00:51:21,320 –> 00:51:22,320
Then batching.
1138
00:51:22,320 –> 00:51:24,320
Python controls how rights happen.
1139
00:51:24,320 –> 00:51:27,720
Chunk sizes back off retry strategy and id impotency keys.
1140
00:51:27,720 –> 00:51:33,000
It writes in batches you can reason about and it records outcomes per batch and per record.
1141
00:51:33,000 –> 00:51:35,840
If a batch fails, you know exactly which records were in it.
1142
00:51:35,840 –> 00:51:40,040
If a retry happens, it doesn’t create duplicate updates because the execution tier treats the
1143
00:51:40,040 –> 00:51:44,600
correlation id plus record identity as a first class id impotency input.
1144
00:51:44,600 –> 00:51:45,920
That’s the deterministic part.
1145
00:51:45,920 –> 00:51:50,320
The same job produces the same outcomes even under retries, even under throttling, even
1146
00:51:50,320 –> 00:51:52,120
under transient failures.
1147
00:51:52,120 –> 00:51:55,040
And now the critical governance rule from earlier stays intact.
1148
00:51:55,040 –> 00:51:57,840
No direct external dataverse exposure.
1149
00:51:57,840 –> 00:52:02,040
Python doesn’t get to talk to dataverse, however at once, just because it’s back end code.
1150
00:52:02,040 –> 00:52:03,920
You still enforce the mediated pattern.
1151
00:52:03,920 –> 00:52:08,600
The execution tier writes through governed endpoints that might be an API behind APIM that
1152
00:52:08,600 –> 00:52:12,080
performs the rights with a controlled identity and logs every operation.
1153
00:52:12,080 –> 00:52:16,200
Or it might be the orchestration tier doing the final commit based on the execution tiers
1154
00:52:16,200 –> 00:52:17,200
output.
1155
00:52:17,200 –> 00:52:20,480
Either way, you don’t let bulk mutation become a free for all just because the code is in
1156
00:52:20,480 –> 00:52:24,840
Python because bulk mutation is where least privilege gets murdered first.
1157
00:52:24,840 –> 00:52:28,160
Engineers get tired of permission errors, so they grant broad roles.
1158
00:52:28,160 –> 00:52:29,400
Makers get tired of failures.
1159
00:52:29,400 –> 00:52:31,280
So they ask for exceptions.
1160
00:52:31,280 –> 00:52:33,320
It’s become permanent entropy wins.
1161
00:52:33,320 –> 00:52:38,240
So you design the right path to be narrow by default, specific tables, specific actions,
1162
00:52:38,240 –> 00:52:40,760
specific scopes and audited principles.
1163
00:52:40,760 –> 00:52:44,240
Now look at what becomes possible once the execution tier owns the bulk job.
1164
00:52:44,240 –> 00:52:50,800
You can return per record status as actual data, updated, skipped, rejected, already compliant,
1165
00:52:50,800 –> 00:52:52,160
conflict detected, and why.
1166
00:52:52,160 –> 00:52:54,960
You can store that in a dataverse table as the job ledger.
1167
00:52:54,960 –> 00:52:58,480
You can produce a human readable summary for the business, but you still keep machine
1168
00:52:58,480 –> 00:53:00,320
readable truth for incident response.
1169
00:53:00,320 –> 00:53:04,200
And you can do the one thing enterprises always pretend they don’t need until they do.
1170
00:53:04,200 –> 00:53:05,200
Prove what happened.
1171
00:53:05,200 –> 00:53:06,800
Not the flow ran successfully.
1172
00:53:06,800 –> 00:53:11,280
What records changed, what values changed, who authorized it, what job produced it, and
1173
00:53:11,280 –> 00:53:16,920
what correlation ID ties every step together across flow, APM and function logs.
1174
00:53:16,920 –> 00:53:19,480
That’s how bulk operations stop being terrifying.
1175
00:53:19,480 –> 00:53:22,080
The flow becomes the request and approval layer.
1176
00:53:22,080 –> 00:53:25,200
Python becomes the deterministic execution engine.
1177
00:53:25,200 –> 00:53:30,040
Azure becomes the enforcement layer that makes identity network and logging non-negotiable.
1178
00:53:30,040 –> 00:53:33,760
And once you’ve solved bulk updates, the next question shows up immediately, usually from
1179
00:53:33,760 –> 00:53:37,160
the same teams that caused the bulk update problem in the first place.
1180
00:53:37,160 –> 00:53:39,960
They want to add just a little AI to the process.
1181
00:53:39,960 –> 00:53:45,600
That’s where things go from expensive to unpredictable if you don’t keep the same tier boundaries.
1182
00:53:45,600 –> 00:53:46,600
Scenario 3.
1183
00:53:46,600 –> 00:53:49,480
ML inference as a govern service, not a maker experiment.
1184
00:53:49,480 –> 00:53:54,920
AI is where the hybrid mandate gets tested because AI tempts people into skipping architecture.
1185
00:53:54,920 –> 00:54:00,240
A maker sees an action that can call an LLM, drops it into a flow, and suddenly the workflow thinks.
1186
00:54:00,240 –> 00:54:02,200
It demos well, it even ships.
1187
00:54:02,200 –> 00:54:04,520
Then finance asks why the monthly bill doubled.
1188
00:54:04,520 –> 00:54:06,840
Legal asks how decisions get explained.
1189
00:54:06,840 –> 00:54:10,520
Security asks where prompts and outputs went, and the business asks the only question that
1190
00:54:10,520 –> 00:54:14,120
matters, why did the same input produce a different result this week?
1191
00:54:14,120 –> 00:54:15,120
This is the risk.
1192
00:54:15,120 –> 00:54:19,880
Embedding inference directly in flows turns cost, behavior, and governance into a probabilistic
1193
00:54:19,880 –> 00:54:20,880
mess.
1194
00:54:20,880 –> 00:54:23,920
The orchestration tier was never designed to be your model runtime, your prompt management
1195
00:54:23,920 –> 00:54:25,440
system, and your safety layer.
1196
00:54:25,440 –> 00:54:28,680
When you force it to be, you get conditional chaos with a token budget.
1197
00:54:28,680 –> 00:54:31,320
So the rule stays consistent with everything else.
1198
00:54:31,320 –> 00:54:34,280
Infrance belongs in the execution tier, not in the orchestration tier.
1199
00:54:34,280 –> 00:54:35,280
The Y is simple.
1200
00:54:35,280 –> 00:54:37,520
ML inference is compute with consequences.
1201
00:54:37,520 –> 00:54:41,480
It needs deterministic rappers even when the model itself is stochastic.
1202
00:54:41,480 –> 00:54:42,480
It needs versioning.
1203
00:54:42,480 –> 00:54:43,480
It needs guardrails.
1204
00:54:43,480 –> 00:54:45,400
It needs auditable inputs and outputs.
1205
00:54:45,400 –> 00:54:48,960
And it needs a place where engineers can fix it without opening 50 flows and praying they
1206
00:54:48,960 –> 00:54:50,560
all use the same prompt.
1207
00:54:50,560 –> 00:54:53,680
In the hybrid pattern, power automate still does what it’s good at.
1208
00:54:53,680 –> 00:54:55,400
It roots the business process.
1209
00:54:55,400 –> 00:54:59,520
It decides when inference should happen, who is allowed to request it, what record it’s
1210
00:54:59,520 –> 00:55:01,280
tied to, and what happens next.
1211
00:55:01,280 –> 00:55:05,440
It does not own the prompt, the retry logic, or the passing of untrusted model output.
1212
00:55:05,440 –> 00:55:06,440
That’s execution.
1213
00:55:06,440 –> 00:55:11,280
So the flow calls a Python service behind APIM, authenticated via Entra, with network
1214
00:55:11,280 –> 00:55:13,680
containment and correlated logging.
1215
00:55:13,680 –> 00:55:15,820
Same as the CSV and bulk update scenarios.
1216
00:55:15,820 –> 00:55:17,440
The only difference is the workload.
1217
00:55:17,440 –> 00:55:21,320
Instead of passing files or batching updates, Python is invoking a model preparing features
1218
00:55:21,320 –> 00:55:22,880
and returning stable outputs.
1219
00:55:22,880 –> 00:55:24,640
Here’s what Python does that flows shouldn’t.
1220
00:55:24,640 –> 00:55:26,400
First, input shaping.
1221
00:55:26,400 –> 00:55:32,000
Most AI in flows failures start with garbage inputs, unbounded text, missing context, sensitive
1222
00:55:32,000 –> 00:55:36,600
fields accidentally included, or random formatting that makes the model behave differently.
1223
00:55:36,600 –> 00:55:39,000
The Python tier normalizes and constraints input.
1224
00:55:39,000 –> 00:55:45,120
It can trim, redact, classify, and reject payloads before they ever hit a model endpoint.
1225
00:55:45,120 –> 00:55:46,120
That’s not optional.
1226
00:55:46,120 –> 00:55:47,120
That’s your safety boundary.
1227
00:55:47,120 –> 00:55:50,080
Second, prompt and configuration versioning.
1228
00:55:50,080 –> 00:55:51,800
Infraints isn’t just call the model.
1229
00:55:51,800 –> 00:55:55,720
It’s a specific prompt template with a specific system message, with specific tool settings,
1230
00:55:55,720 –> 00:56:00,160
with specific temperature and max tokens, and often with specific grounding data.
1231
00:56:00,160 –> 00:56:04,440
If that configuration lives inside a flow action, you’ve turned prompt engineering into a distributed
1232
00:56:04,440 –> 00:56:06,480
configuration drift problem.
1233
00:56:06,480 –> 00:56:09,280
Every copied flow becomes its own model behavior fork.
1234
00:56:09,280 –> 00:56:12,440
Nobody can answer which version is running where entropy wins again.
1235
00:56:12,440 –> 00:56:15,920
So the execution tier owns prompt versions like code artifacts.
1236
00:56:15,920 –> 00:56:18,920
Version identifiers become part of the response contract.
1237
00:56:18,920 –> 00:56:20,920
And the business asks why behavior changed?
1238
00:56:20,920 –> 00:56:22,200
You don’t argue about vibes.
1239
00:56:22,200 –> 00:56:24,560
You point to a version and a change record.
1240
00:56:24,560 –> 00:56:27,960
Third, guard rails and deterministic post processing.
1241
00:56:27,960 –> 00:56:31,160
Model outputs are not structured until you force them to be.
1242
00:56:31,160 –> 00:56:34,760
Flows tend to treat model text like truth and then pass it with expressions that break
1243
00:56:34,760 –> 00:56:36,680
the moment the model gets creative.
1244
00:56:36,680 –> 00:56:41,840
The Python tier can enforce strict output schemers, validate fields, reject malformed results,
1245
00:56:41,840 –> 00:56:44,240
and apply deterministic rules that the business can audit.
1246
00:56:44,240 –> 00:56:46,680
The model can suggest the service decides what counts.
1247
00:56:46,680 –> 00:56:49,280
The uncomfortable truth executives need to hear.
1248
00:56:49,280 –> 00:56:50,920
AI doesn’t replace policy.
1249
00:56:50,920 –> 00:56:55,120
AI needs policy codified because otherwise it becomes a liability generator.
1250
00:56:55,120 –> 00:56:56,320
So what comes back to the flow?
1251
00:56:56,320 –> 00:56:57,320
Not raw text.
1252
00:56:57,320 –> 00:56:59,400
Not here’s the model’s opinion.
1253
00:56:59,400 –> 00:57:02,960
The execution tier returns stable bounded outputs.
1254
00:57:02,960 –> 00:57:08,080
A classification label, a confident score if you choose to expose it, a set of extracted fields,
1255
00:57:08,080 –> 00:57:11,480
a decision recommendation with a reason code and any warnings.
1256
00:57:11,480 –> 00:57:15,320
If the model can’t comply with the schema, the service returns a failure type.
1257
00:57:15,320 –> 00:57:20,280
The orchestration tier can root, retry, human review or reject.
1258
00:57:20,280 –> 00:57:22,640
Now you get the enterprise behaviors you actually want.
1259
00:57:22,640 –> 00:57:26,960
Cost becomes governable because APM can throttle and you can measure token usage at the service
1260
00:57:26,960 –> 00:57:29,760
boundary instead of hiding it in flow runs.
1261
00:57:29,760 –> 00:57:34,560
Behavior becomes governable because prompts and passing live in one place with version control.
1262
00:57:34,560 –> 00:57:39,120
Auditability becomes possible because you can log inputs, outputs and config versions
1263
00:57:39,120 –> 00:57:42,720
with correlation IDs tied back to the flow run and the dataverse record.
1264
00:57:42,720 –> 00:57:47,480
And you can finally separate AI experimentation from AI in production without pretending
1265
00:57:47,480 –> 00:57:48,800
makers won’t experiment.
1266
00:57:48,800 –> 00:57:50,520
They will, they should.
1267
00:57:50,520 –> 00:57:54,920
But experiments belong in a green zone with controls, not in production flows that approve
1268
00:57:54,920 –> 00:57:59,840
payments, update customer records or trigger compliance actions.
1269
00:57:59,840 –> 00:58:02,600
The hybrid mandate doesn’t ban AI in power platform.
1270
00:58:02,600 –> 00:58:07,440
It contains it.flowstays orchestration, python does execution, Azure enforces governance.
1271
00:58:07,440 –> 00:58:12,000
And inference becomes a service with contracts, boundaries and evidence rather than a maker
1272
00:58:12,000 –> 00:58:16,200
experiment that slowly turns into policy drift with an invoice.
1273
00:58:16,200 –> 00:58:20,520
Scaling reality, limits, throttles and the conditional chaos tax.
1274
00:58:20,520 –> 00:58:24,480
Scale is where your architecture stops being an opinion and starts being a physics problem.
1275
00:58:24,480 –> 00:58:28,880
Power automate has run limits, connectors have throttles, dataverse has service protection
1276
00:58:28,880 –> 00:58:34,080
limits, APM has quotas, functions have execution timeouts, none of these are negotiable and none
1277
00:58:34,080 –> 00:58:37,080
of them care that a VP needs the workflow by Friday.
1278
00:58:37,080 –> 00:58:40,880
So when an automation succeeds and gets adopted it immediately becomes a scaling test
1279
00:58:40,880 –> 00:58:42,560
you didn’t design for.
1280
00:58:42,560 –> 00:58:48,160
Volume rises, concurrency rises, payload sizes creep up because someone adds just one more
1281
00:58:48,160 –> 00:58:49,160
field.
1282
00:58:49,160 –> 00:58:52,520
And then the platform does what distributed systems always do.
1283
00:58:52,520 –> 00:58:56,720
It applies back pressure, starts rejecting calls and forces you to learn the difference between
1284
00:58:56,720 –> 00:58:59,440
a deterministic system and a probabilistic one.
1285
00:58:59,440 –> 00:59:01,200
Here’s what most people miss.
1286
00:59:01,200 –> 00:59:03,560
Throttling doesn’t just slow you down, it changes behavior.
1287
00:59:03,560 –> 00:59:06,200
A flow that hits connector limits doesn’t fail cleanly.
1288
00:59:06,200 –> 00:59:10,400
It retries, it delays, it sometimes partially completes depending on where it hits the limit.
1289
00:59:10,400 –> 00:59:14,000
And because many flows don’t implement identity, retries don’t replay safely.
1290
00:59:14,000 –> 00:59:18,000
They duplicate work, they create conflicting updates, they send duplicate emails, they create
1291
00:59:18,000 –> 00:59:21,480
double approvals, they write the same record twice with two different values depending
1292
00:59:21,480 –> 00:59:23,360
on what data changed between attempts.
1293
00:59:23,360 –> 00:59:25,080
That’s the conditional chaos tax.
1294
00:59:25,080 –> 00:59:29,000
Not because power platform is unreliable, because your design assumed linear execution in
1295
00:59:29,000 –> 00:59:31,720
a world that enforces distributed constraints.
1296
00:59:31,720 –> 00:59:35,960
So treat scaling as a first class boundary decision, not a performance afterthought.
1297
00:59:35,960 –> 00:59:37,880
The orchestration tier needs to stay lean.
1298
00:59:37,880 –> 00:59:41,440
That is not a preference, it’s the only way the system remains survivable when adoption
1299
00:59:41,440 –> 00:59:42,600
doubles.
1300
00:59:42,600 –> 00:59:46,520
Every extra action in a flow is an additional failure surface.
1301
00:59:46,520 –> 00:59:50,560
Another timeout, another connector dependency, another retry path, another place where errors
1302
00:59:50,560 –> 00:59:53,280
can be swallowed and re-emitted as unknown.
1303
00:59:53,280 –> 00:59:57,040
And yes, people will argue that low code makes it easy to add steps.
1304
00:59:57,040 –> 01:00:00,720
That’s exactly the problem, it’s easy to add steps that become permanent, it’s easy to
1305
01:00:00,720 –> 01:00:05,000
add exceptions that become policy, it’s easy to keep shipping until you have a flow that
1306
01:00:05,000 –> 01:00:10,000
is effectively a data pipeline with a UI and those fail in slow, expensive, non-deterministic
1307
01:00:10,000 –> 01:00:11,000
ways.
1308
01:00:11,000 –> 01:00:15,000
So the hybrid mandate applies the same pressure as before, move compute out, keep coordination
1309
01:00:15,000 –> 01:00:16,000
in.
1310
01:00:16,000 –> 01:00:19,800
If you’re doing bulk operations, don’t loop through 10,000 records in power automate because
1311
01:00:19,800 –> 01:00:20,800
you can.
1312
01:00:20,800 –> 01:00:24,800
You will hit limits and the work around engineering will turn into the real logic.
1313
01:00:24,800 –> 01:00:29,240
Put the bulk work in Python behind APIM where you can control batching, apply back off and
1314
01:00:29,240 –> 01:00:31,160
implement idempotency properly.
1315
01:00:31,160 –> 01:00:36,720
If you’re doing heavy transforms, don’t pass and normalize in a flow because it’s just strings.
1316
01:00:36,720 –> 01:00:41,400
That turns into nested loops, fragile expressions and a debugging model that depends on run
1317
01:00:41,400 –> 01:00:42,960
history archaeology.
1318
01:00:42,960 –> 01:00:47,320
Do it in the execution tier where you can test it, version it and run it deterministically.
1319
01:00:47,320 –> 01:00:50,920
And when you do keep orchestration in the flow, you still need to respect the platform’s
1320
01:00:50,920 –> 01:00:51,920
shape.
1321
01:00:51,920 –> 01:00:53,600
Retrieves should be intentional, not accidental.
1322
01:00:53,600 –> 01:00:57,800
If a call fails, you should know whether you’re retrying because it was transient or because
1323
01:00:57,800 –> 01:01:00,080
you hit a quarter that won’t clear for an hour.
1324
01:01:00,080 –> 01:01:04,840
That means your execution tier needs failure types that the orchestration tier can root,
1325
01:01:04,840 –> 01:01:10,400
throttled, unauthorized, validation error, downstream unavailable timeout.
1326
01:01:10,400 –> 01:01:13,680
If everything comes back as 500, the flow can’t behave intelligently.
1327
01:01:13,680 –> 01:01:16,640
It will just try again until it makes the situation worse.
1328
01:01:16,640 –> 01:01:18,280
This is where APIM earns its keep again.
1329
01:01:18,280 –> 01:01:21,840
You throttle at the edge, you don’t let a thousand parallel flows stampede the back end
1330
01:01:21,840 –> 01:01:24,040
because someone turned on concurrency.
1331
01:01:24,040 –> 01:01:26,200
You apply quotas per client identity.
1332
01:01:26,200 –> 01:01:30,280
You enforce payload limits so you don’t get surprised 20 metabyte JSON bodies because someone
1333
01:01:30,280 –> 01:01:33,480
decided to send the entire spreadsheet to be safe.
1334
01:01:33,480 –> 01:01:38,240
You reject early, consistently and with a reason code, the orchestration tier can understand.
1335
01:01:38,240 –> 01:01:40,040
And when you need real scale, you queue.
1336
01:01:40,040 –> 01:01:41,040
Cues aren’t trendy.
1337
01:01:41,040 –> 01:01:45,520
They’re how you turn bursty, user-driven orchestration into steady, governable execution.
1338
01:01:45,520 –> 01:01:46,760
The flow submits a job.
1339
01:01:46,760 –> 01:01:49,800
The execution tier pulls and processes at a controlled rate.
1340
01:01:49,800 –> 01:01:51,840
The flow track state and notifies humans.
1341
01:01:51,840 –> 01:01:55,720
That’s orchestration behaving like orchestration instead of pretending to be a compute engine.
1342
01:01:55,720 –> 01:02:00,960
Now the cost part because cost is where executives suddenly develop strong opinions about architecture.
1343
01:02:00,960 –> 01:02:04,760
Power automate costs scale with runs and premium connectors.
1344
01:02:04,760 –> 01:02:07,160
Execution tier costs scale with compute and throughput.
1345
01:02:07,160 –> 01:02:11,640
If you keep pushing compute into flows, you pay for orchestration to do execution poorly.
1346
01:02:11,640 –> 01:02:16,200
And if you push compute into Python services, you pay for execution to do execution well.
1347
01:02:16,200 –> 01:02:20,120
The hybrid mandate is the only model that lets you choose deliberately which cost curve
1348
01:02:20,120 –> 01:02:21,440
you want.
1349
01:02:21,440 –> 01:02:22,880
Scaling doesn’t reward optimism.
1350
01:02:22,880 –> 01:02:24,120
It rewards boundaries.
1351
01:02:24,120 –> 01:02:28,120
And if you don’t enforce those boundaries early, you’ll enforce them later under incident
1352
01:02:28,120 –> 01:02:30,800
pressure with angry stakeholders and unclear ownership.
1353
01:02:30,800 –> 01:02:35,240
That’s the most expensive way to learn platform limits, so treat limits and throttles as architectural
1354
01:02:35,240 –> 01:02:40,960
inputs designed for back pressure, enforce id-impotency, throttle at APIM.
1355
01:02:40,960 –> 01:02:43,440
Queue when volume isn’t polite.
1356
01:02:43,440 –> 01:02:49,200
Otherwise success becomes a tax you pay in conditional C, alum discipline, versioned contracts,
1357
01:02:49,200 –> 01:02:50,680
not version screenshots.
1358
01:02:50,680 –> 01:02:53,920
Once the hybrid pattern works, the enterprise does what it always does.
1359
01:02:53,920 –> 01:02:58,360
It promotes the prototype to production by continuing to rely on it, not through a formal
1360
01:02:58,360 –> 01:03:00,040
release, through repetition.
1361
01:03:00,040 –> 01:03:04,120
And that’s where ALM either shows up as architecture or disappears as ceremony.
1362
01:03:04,120 –> 01:03:08,840
Power platform teams often treat life cycle management as export the flow and import the flow.
1363
01:03:08,840 –> 01:03:10,600
That’s not life cycle management.
1364
01:03:10,600 –> 01:03:14,040
That’s file movement, it preserves an artifact, but it doesn’t preserve intent, it doesn’t
1365
01:03:14,040 –> 01:03:17,520
preserve dependency versions, it doesn’t preserve contracts, and it absolutely doesn’t
1366
01:03:17,520 –> 01:03:21,000
preserve the one thing that matters when systems drift, a traceable change story.
1367
01:03:21,000 –> 01:03:25,200
In hybrid automation, ALM has to be centered on contracts, not canvas, because the boundary
1368
01:03:25,200 –> 01:03:28,280
between orchestration and execution is not a diagram.
1369
01:03:28,280 –> 01:03:33,480
It’s an agreement, what inputs are allowed, what outputs are guaranteed, what failures mean,
1370
01:03:33,480 –> 01:03:34,800
and what gets logged.
1371
01:03:34,800 –> 01:03:39,320
If that agreement changes silently, you don’t get a neat failure, you get a slow governance
1372
01:03:39,320 –> 01:03:44,560
leak, makers implement workarounds, engineers add temporary compatibility, and within a
1373
01:03:44,560 –> 01:03:48,520
quarter you’ve rebuilt the same entropy generator you were trying to escape.
1374
01:03:48,520 –> 01:03:52,880
So the first rule is blunt version the API contract like it’s a product because it is.
1375
01:03:52,880 –> 01:03:58,280
If the Python execution tier exposes endpoints behind APIM, those endpoints need explicit versions,
1376
01:03:58,280 –> 01:04:02,320
not will keep it compatible, not it’s just internal.
1377
01:04:02,320 –> 01:04:06,160
Internal API is break more businesses than external ones because nobody budgets for internal
1378
01:04:06,160 –> 01:04:07,160
change management.
1379
01:04:07,160 –> 01:04:12,080
So you publish V1, you add V2 when behavior changes, you deprecate with the timeline, and
1380
01:04:12,080 –> 01:04:16,480
you use APM analytics to see which flows still call V1 because otherwise your deprecation
1381
01:04:16,480 –> 01:04:18,000
plan is a fantasy.
1382
01:04:18,000 –> 01:04:22,760
The second rule, treat Python dependencies as production supply chain, not as a maker convenience.
1383
01:04:22,760 –> 01:04:27,720
A requirements dot dxt that changes because someone ran PIP install locally is not an enterprise
1384
01:04:27,720 –> 01:04:28,840
artifact.
1385
01:04:28,840 –> 01:04:34,240
The execution tier needs PINT dependencies, repeatable builds, and a controlled promotion path.
1386
01:04:34,240 –> 01:04:38,080
Otherwise you will eventually redeploy a function and discover that a transitive dependency
1387
01:04:38,080 –> 01:04:43,560
updated behavior changed and the workflow now produces different outputs for the same input.
1388
01:04:43,560 –> 01:04:48,080
That’s not Python being risky, that’s you refusing to manage the execution tier as software
1389
01:04:48,080 –> 01:04:52,960
and yes the same applies to prompts and model configurations if you’re doing inference.
1390
01:04:52,960 –> 01:04:53,960
Configuration is code.
1391
01:04:53,960 –> 01:04:58,760
If it can change behavior it must be versioned, reviewed, and released with traceability.
1392
01:04:58,760 –> 01:05:03,200
Now the power platform side, flows, apps, and solutions also need discipline but not
1393
01:05:03,200 –> 01:05:04,680
the fake kind.
1394
01:05:04,680 –> 01:05:08,760
And screenshots are what teams produce when they don’t have deployment artifacts.
1395
01:05:08,760 –> 01:05:11,800
Here’s the run history, here’s the screenshot of the trigger.
1396
01:05:11,800 –> 01:05:15,600
Here’s the expression that worked, that’s documentation of accidents, not documentation
1397
01:05:15,600 –> 01:05:16,600
of design.
1398
01:05:16,600 –> 01:05:22,600
Real ALM means the flow lives in a solution, uses environment variables, references connections
1399
01:05:22,600 –> 01:05:27,360
that are created intentionally, and gets promoted through dev, test, and prod like any other
1400
01:05:27,360 –> 01:05:28,840
artifact.
1401
01:05:28,840 –> 01:05:31,320
Environment separation is not negotiable in the hybrid mandate.
1402
01:05:31,320 –> 01:05:35,760
If Dev and prod share the same API, the same identities in the same dataverse tables you
1403
01:05:35,760 –> 01:05:40,040
don’t have environments, you have one environment with extra steps.
1404
01:05:40,040 –> 01:05:41,560
Separation is what makes change safe.
1405
01:05:41,560 –> 01:05:46,640
Dev calls dev APM, test calls test APM, prod calls prod APM, and the identities are separate
1406
01:05:46,640 –> 01:05:50,520
because permissions drift differently in each place and you need the ability to revoke,
1407
01:05:50,520 –> 01:05:54,000
rotate, and audit without breaking everything at once.
1408
01:05:54,000 –> 01:05:57,960
Promotion should be gated on traceability, which flow version, which API version, which
1409
01:05:57,960 –> 01:06:03,160
Python build, which dependency set, which APIM policy set, if you can’t answer that on demand,
1410
01:06:03,160 –> 01:06:07,200
you are not operating a system, you are operating a coincidence, and here’s the part that makes
1411
01:06:07,200 –> 01:06:09,080
people uncomfortable.
1412
01:06:09,080 –> 01:06:13,080
Ownership has to follow the artifacts, makers can own orchestration logic, but they cannot
1413
01:06:13,080 –> 01:06:16,040
be the release managers for execution code.
1414
01:06:16,040 –> 01:06:19,360
Engineers can own execution services, but they cannot be the only people who understand
1415
01:06:19,360 –> 01:06:21,240
when a business process changes.
1416
01:06:21,240 –> 01:06:25,160
Platform teams can own identities and policies, but they cannot be the catch all for every,
1417
01:06:25,160 –> 01:06:27,040
it stopped working complaint.
1418
01:06:27,040 –> 01:06:32,360
So you need a release contract across teams, makers, change flows, engineers, change services,
1419
01:06:32,360 –> 01:06:37,440
platform governs the boundaries, and everyone agrees on what constitutes a breaking change,
1420
01:06:37,440 –> 01:06:40,200
because the hybrid mandate is not low code plus Python.
1421
01:06:40,200 –> 01:06:42,640
It’s a system where drift is expected and managed.
1422
01:06:42,640 –> 01:06:44,400
RM is the drift management layer.
1423
01:06:44,400 –> 01:06:47,760
Without it, your 3-tier model collapses back into improvisation.
1424
01:06:47,760 –> 01:06:50,840
With it, you get the only real enterprise outcome.
1425
01:06:50,840 –> 01:06:54,840
Stable orchestration, deterministic execution, and governance that survives the next
1426
01:06:54,840 –> 01:06:55,840
year.
1427
01:06:55,840 –> 01:06:59,600
Operating model, COE as entropy management, not a maker police.
1428
01:06:59,600 –> 01:07:03,280
The hybrid mandate dies in most organizations for a boring reason.
1429
01:07:03,280 –> 01:07:08,720
Nobody owns the space between maker velocity and enterprise responsibility, so the platform
1430
01:07:08,720 –> 01:07:09,720
drifts.
1431
01:07:09,720 –> 01:07:13,680
Not because people are reckless, because the operating model doesn’t exist, and systems
1432
01:07:13,680 –> 01:07:16,080
will always root around missing structure.
1433
01:07:16,080 –> 01:07:19,320
That’s what the center of excellence is for, not as a governance theatre committee,
1434
01:07:19,320 –> 01:07:22,800
not as the department of note as entropy management.
1435
01:07:22,800 –> 01:07:26,680
Because the work isn’t stopping makers from building things, that’s impossible.
1436
01:07:26,680 –> 01:07:29,880
The work is preventing the accumulation of invisible exceptions.
1437
01:07:29,880 –> 01:07:34,840
One-off connectors, ad hoc service accounts, copy pasted flows, unversioned endpoints, and
1438
01:07:34,840 –> 01:07:38,080
temporary bypasses that become permanent dependencies.
1439
01:07:38,080 –> 01:07:41,840
A COE that behaves like maker police creates a predictable failure mode.
1440
01:07:41,840 –> 01:07:46,000
Makers go quiet, they build anyway, they stop asking questions, solutions move into the dark,
1441
01:07:46,000 –> 01:07:50,040
and the first time leadership hears about it is during an audit or after an incident,
1442
01:07:50,040 –> 01:07:51,760
when the response is always the same.
1443
01:07:51,760 –> 01:07:53,560
How did we not know this existed?
1444
01:07:53,560 –> 01:07:55,720
So the COE has to be positioned differently.
1445
01:07:55,720 –> 01:08:00,360
The COE is the team that curates the enterprise patterns that make hybrid safe.
1446
01:08:00,360 –> 01:08:04,680
Reference architectures, approved integration paths, and the boundary rules that keep orchestration
1447
01:08:04,680 –> 01:08:09,120
low-code, execution deterministic, and governance enforceable in Azure.
1448
01:08:09,120 –> 01:08:13,240
The COE doesn’t build every solution, it builds the rails that make solutions survivable,
1449
01:08:13,240 –> 01:08:15,760
that means the COE owns four concrete things.
1450
01:08:15,760 –> 01:08:17,600
First, portfolio visibility.
1451
01:08:17,600 –> 01:08:18,840
Not a vanity inventory.
1452
01:08:18,840 –> 01:08:21,320
An actual portfolio with classification.
1453
01:08:21,320 –> 01:08:22,320
Productivity.
1454
01:08:22,320 –> 01:08:23,680
Team workflow.
1455
01:08:23,680 –> 01:08:25,160
Departmental system.
1456
01:08:25,160 –> 01:08:26,360
Enterprise workflow.
1457
01:08:26,360 –> 01:08:27,360
Regulated workflow.
1458
01:08:27,360 –> 01:08:29,880
Those categories determine which guard rails apply.
1459
01:08:29,880 –> 01:08:32,800
If everything gets treated like production, delivery freezes.
1460
01:08:32,800 –> 01:08:35,960
If nothing gets treated like production, entropy wins.
1461
01:08:35,960 –> 01:08:38,000
Classification is the compromise that scales.
1462
01:08:38,000 –> 01:08:39,840
Second, patterns and reusable assets.
1463
01:08:39,840 –> 01:08:42,920
The COE should publish the standard integration contracts.
1464
01:08:42,920 –> 01:08:44,600
How a flow calls an API?
1465
01:08:44,600 –> 01:08:48,880
Where correlation IDs come from, what APIM policies are non-negotiable, what an error response
1466
01:08:48,880 –> 01:08:51,960
looks like, what “ident potent” means in this tenant.
1467
01:08:51,960 –> 01:08:53,640
Makers don’t need a 90-page document.
1468
01:08:53,640 –> 01:08:57,520
They need a template and a reference implementation that works the first time.
1469
01:08:57,520 –> 01:08:59,480
Third, the escalation path.
1470
01:08:59,480 –> 01:09:00,840
Fusion teams are not a slogan.
1471
01:09:00,840 –> 01:09:02,320
They’re an operating model.
1472
01:09:02,320 –> 01:09:06,080
Citizen makers own orchestration logic and business process.
1473
01:09:06,080 –> 01:09:08,000
Engineers own the execution tier.
1474
01:09:08,000 –> 01:09:09,000
Python services.
1475
01:09:09,000 –> 01:09:10,000
Packaging.
1476
01:09:10,000 –> 01:09:11,000
Dependency pinning.
1477
01:09:11,000 –> 01:09:12,000
Performance.
1478
01:09:12,000 –> 01:09:13,000
And reliability.
1479
01:09:13,000 –> 01:09:15,360
Platform teams own the governance tier.
1480
01:09:15,360 –> 01:09:20,920
For identities, network boundaries, secrets, logging and policy enforcement, the COE coordinates
1481
01:09:20,920 –> 01:09:24,120
those handoffs, so work doesn’t stall in politics.
1482
01:09:24,120 –> 01:09:27,080
Fourth, enforcement mechanisms that don’t rely on willpower.
1483
01:09:27,080 –> 01:09:31,680
DLP policies, environment strategy, managed environments, connector governance, APM policy
1484
01:09:31,680 –> 01:09:33,800
baselines and identity standards.
1485
01:09:33,800 –> 01:09:37,920
The COE should define what’s allowed but also make the allowed path the easiest path.
1486
01:09:37,920 –> 01:09:42,360
If the secure path is harder than the insecure path, you’ve built a lesson in architectural
1487
01:09:42,360 –> 01:09:43,360
erosion.
1488
01:09:43,360 –> 01:09:45,080
Now the part everyone avoids, intake.
1489
01:09:45,080 –> 01:09:48,840
We need a clear rule for when a flow qualifies for the execution tier.
1490
01:09:48,840 –> 01:09:53,120
Not because makers can’t do it, because the organization can’t afford every complex automation
1491
01:09:53,120 –> 01:09:55,440
to become a bespoke debugging exercise.
1492
01:09:55,440 –> 01:09:57,880
So the intake criteria should be mechanical.
1493
01:09:57,880 –> 01:10:00,320
Data transforms beyond simple mapping.
1494
01:10:00,320 –> 01:10:05,280
bulk operations above a threshold, long running jobs, ML inference, cross-environment integration,
1495
01:10:05,280 –> 01:10:08,800
and anything that touches regulated data with non-trivial logic.
1496
01:10:08,800 –> 01:10:13,600
When those triggers appear, the COE roots the work into the hybrid pattern.
1497
01:10:13,600 –> 01:10:17,560
It’s a great, empowered platform, execute in Python, govern in Azure, and the COE has
1498
01:10:17,560 –> 01:10:20,000
to defend that boundary in both directions.
1499
01:10:20,000 –> 01:10:24,160
It needs to stop makers from smuggling execution into flows through scopes, baguette and connector
1500
01:10:24,160 –> 01:10:25,160
abuse.
1501
01:10:25,160 –> 01:10:29,680
But it also needs to stop engineers from bypassing orchestration and building shadow services
1502
01:10:29,680 –> 01:10:32,480
that mutate dataverse without process visibility.
1503
01:10:32,480 –> 01:10:36,720
Both our entropy generators both feel justified in the moment, both become permanent.
1504
01:10:36,720 –> 01:10:39,320
This is why the COE’s job is not approval.
1505
01:10:39,320 –> 01:10:41,760
It’s alignment.
1506
01:10:41,760 –> 01:10:47,200
It means every hybrid solution has an accountable orchestration owner, an accountable execution
1507
01:10:47,200 –> 01:10:49,360
owner, and an accountable governance owner.
1508
01:10:49,360 –> 01:10:51,840
If any of those are missing, the solution is already abandoned.
1509
01:10:51,840 –> 01:10:53,000
It just hasn’t failed yet.
1510
01:10:53,000 –> 01:10:55,480
And finally, the COE needs to measure drift.
1511
01:10:55,480 –> 01:10:58,080
Not with vanity metrics like number of apps.
1512
01:10:58,080 –> 01:11:02,680
With indicators that predict incidents, number of public endpoints, number of flows using
1513
01:11:02,680 –> 01:11:07,360
personal connections, number of APIs without versioning, number of workloads without correlated
1514
01:11:07,360 –> 01:11:12,000
logging and number of solutions living only in the default environment.
1515
01:11:12,000 –> 01:11:15,480
Those are the cracks where chaos enters, and mature COE doesn’t block progress.
1516
01:11:15,480 –> 01:11:20,320
It makes progress repeatable, and that’s the entire point of the hybrid mandate, agility,
1517
01:11:20,320 –> 01:11:24,280
but with discipline enforced by design, not by optimism.
1518
01:11:24,280 –> 01:11:28,480
Executive risk framing, what you’re actually buying with the hybrid mandate.
1519
01:11:28,480 –> 01:11:30,640
Executives don’t approve architecture diagrams.
1520
01:11:30,640 –> 01:11:34,280
They approve risk trades, and the reason the hybrid mandate matters is that it converts
1521
01:11:34,280 –> 01:11:38,160
a set of vague emotional arguments into measurable enforceable properties.
1522
01:11:38,160 –> 01:11:41,720
Mostly, the ship teams think they’re buying speed when they fund power platform.
1523
01:11:41,720 –> 01:11:42,720
They’re not.
1524
01:11:42,720 –> 01:11:45,800
They’re buying the ability to push decision making closer to the business without collapsing
1525
01:11:45,800 –> 01:11:46,800
governance.
1526
01:11:46,800 –> 01:11:51,200
That distinction matters because if the only lever you pull is velocity, the organization
1527
01:11:51,200 –> 01:11:53,080
will absolutely achieve velocity.
1528
01:11:53,080 –> 01:11:57,200
It will just be velocity towards sprawl inconsistent controls and operational ambiguity.
1529
01:11:57,200 –> 01:11:58,640
The platform doesn’t stop that.
1530
01:11:58,640 –> 01:11:59,640
It enables it.
1531
01:11:59,640 –> 01:12:02,480
So here’s what you’re actually buying with the hybrid mandate.
1532
01:12:02,480 –> 01:12:05,520
Lower incident costs through determinism.
1533
01:12:05,520 –> 01:12:07,440
Incidents are expensive for one reason.
1534
01:12:07,440 –> 01:12:09,160
Nobody can agree on what happened.
1535
01:12:09,160 –> 01:12:13,640
The bridge called Bern’s time reconstructing reality across flow runs, connect the behavior,
1536
01:12:13,640 –> 01:12:15,480
and back end logs that don’t line up.
1537
01:12:15,480 –> 01:12:20,400
The hybrid mandate forces a deterministic execution tier with correlated logging and enforced
1538
01:12:20,400 –> 01:12:21,400
contracts.
1539
01:12:21,400 –> 01:12:23,440
That means failures stop being interpretive.
1540
01:12:23,440 –> 01:12:24,640
They become traceable.
1541
01:12:24,640 –> 01:12:28,120
Your mean time to innocence drops, which is the only metric leadership should care about
1542
01:12:28,120 –> 01:12:29,360
during an outage.
1543
01:12:29,360 –> 01:12:31,440
And your mean time to resolution follows.
1544
01:12:31,440 –> 01:12:32,440
Second.
1545
01:12:32,440 –> 01:12:36,320
You lose security exposure through fewer parts to sensitive data.
1546
01:12:36,320 –> 01:12:38,280
Security teams don’t lose sleep over a flow.
1547
01:12:38,280 –> 01:12:42,560
They lose sleep over uncontrolled identities sprawl and unmanaged egress.
1548
01:12:42,560 –> 01:12:46,560
When data verse becomes directly reachable from arbitrary runtimes, you increase the number
1549
01:12:46,560 –> 01:12:49,680
of principles, endpoints, and data paths that can leak.
1550
01:12:49,680 –> 01:12:51,200
That is the blast radius problem.
1551
01:12:51,200 –> 01:12:56,600
The hybrid mandate shrinks the blast radius by forcing data access through governed boundaries.
1552
01:12:56,600 –> 01:13:00,680
Entra workload identity, network containment, and policy enforcement at the API edge.
1553
01:13:00,680 –> 01:13:03,040
You don’t eliminate risk, you stop multiplying it.
1554
01:13:03,040 –> 01:13:04,040
Third.
1555
01:13:04,040 –> 01:13:06,760
Reduced compliance, pain through evidence, not assertions.
1556
01:13:06,760 –> 01:13:08,920
Compliance audits are not asking whether you have policies.
1557
01:13:08,920 –> 01:13:11,280
They’re asking whether policies survive pressure.
1558
01:13:11,280 –> 01:13:14,680
The hybrid mandate gives you artifacts auditors can understand.
1559
01:13:14,680 –> 01:13:19,120
Versioned APIs, consistent authentication, bounded payloads, and end-to-end traces tied to
1560
01:13:19,120 –> 01:13:20,800
a correlation ID.
1561
01:13:20,800 –> 01:13:25,720
That turns, we think it’s controlled into, here is the record of the decision, the execution,
1562
01:13:25,720 –> 01:13:27,000
and the commit.
1563
01:13:27,000 –> 01:13:30,640
Audit conversations get shorter when you can show proof without assembling a narrative.
1564
01:13:30,640 –> 01:13:34,840
Both reduced vendor lock-in risk by separating orchestration from execution.
1565
01:13:34,840 –> 01:13:36,280
This is where people get confused.
1566
01:13:36,280 –> 01:13:38,440
The hybrid mandate is not anti-power platform.
1567
01:13:38,440 –> 01:13:39,440
It’s pro-boundary.
1568
01:13:39,440 –> 01:13:43,000
When you bury your business logic inside flows, you hardwire your enterprise behavior
1569
01:13:43,000 –> 01:13:46,240
to a tool that was designed for orchestration, not compute.
1570
01:13:46,240 –> 01:13:50,200
Over time, every workaround becomes a dependency and migration becomes a rewrite.
1571
01:13:50,200 –> 01:13:54,640
When you externalize deterministic logic into Python services behind stable contracts,
1572
01:13:54,640 –> 01:13:57,800
you create portability, not because you plan to leave, because you want the option
1573
01:13:57,800 –> 01:13:59,720
to evolve without ransom.
1574
01:13:59,720 –> 01:14:01,800
And can change platforms later.
1575
01:14:01,800 –> 01:14:05,040
Execution services can be reused, governance controls remain enforceable.
1576
01:14:05,040 –> 01:14:08,800
Fifth, better talent alignment and lower organizational friction.
1577
01:14:08,800 –> 01:14:12,680
Citizen makers should not be carrying the responsibility for runtime patching, dependency
1578
01:14:12,680 –> 01:14:14,800
management, and API design.
1579
01:14:14,800 –> 01:14:18,720
Engineers should not be writing approval workflows and chasing inbox rules.
1580
01:14:18,720 –> 01:14:21,560
The hybrid mandate makes ownership legible.
1581
01:14:21,560 –> 01:14:26,560
Makers own process orchestration, engineers own execution services, and the platform team
1582
01:14:26,560 –> 01:14:28,160
owns the governance tier.
1583
01:14:28,160 –> 01:14:33,280
It reduces the constant debate over who broke it, because the boundaries define accountability
1584
01:14:33,280 –> 01:14:35,640
before production defines it for you.
1585
01:14:35,640 –> 01:14:39,560
Now the uncomfortable executive reality, you are not funding a feature.
1586
01:14:39,560 –> 01:14:41,600
You are funding an operating model.
1587
01:14:41,600 –> 01:14:46,680
If leadership mandates low-code only, they are choosing a probabilistic security model,
1588
01:14:46,680 –> 01:14:50,280
because policy exceptions will accumulate until the system behaves differently in each
1589
01:14:50,280 –> 01:14:51,960
corner of the tenant.
1590
01:14:51,960 –> 01:14:55,800
If leadership mandates pro-code only, they are choosing a delivery bottleneck, because
1591
01:14:55,800 –> 01:14:59,760
the backlog will outgrow the team and shadow IT will happen anyway.
1592
01:14:59,760 –> 01:15:04,080
The hybrid mandate is the only position that survives entropy, low-code where orchestration
1593
01:15:04,080 –> 01:15:08,400
is the value, Python where determinism is required, and Azure where governance must
1594
01:15:08,400 –> 01:15:10,080
be enforced by design.
1595
01:15:10,080 –> 01:15:14,920
And that’s the executive purchase, fewer ambiguous outages, fewer uncontrolled data paths,
1596
01:15:14,920 –> 01:15:20,480
fewer audit surprises, and a platform that scales without turning into conditional chaos.
1597
01:15:20,480 –> 01:15:24,320
Closing executive positioning, a maturity model, not a rebellion.
1598
01:15:24,320 –> 01:15:28,240
The executive positioning has to be explicit, because otherwise the organization will hear
1599
01:15:28,240 –> 01:15:29,560
what it wants to hear.
1600
01:15:29,560 –> 01:15:32,320
Some will hear “power platform is unsafe.”
1601
01:15:32,320 –> 01:15:35,160
Others will hear “engineering” wants to take control back.
1602
01:15:35,160 –> 01:15:38,480
And makers will hear “it is about to slow everything down again.”
1603
01:15:38,480 –> 01:15:40,040
All of those interpretations are wrong.
1604
01:15:40,040 –> 01:15:42,120
The hybrid mandate is not anti-power platform.
1605
01:15:42,120 –> 01:15:44,160
Power platform is the orchestration tier.
1606
01:15:44,160 –> 01:15:45,480
That’s not a consolation price.
1607
01:15:45,480 –> 01:15:49,600
That’s the part of the system that touches humans, process, approvals and business state.
1608
01:15:49,600 –> 01:15:51,080
It’s where intent gets expressed.
1609
01:15:51,080 –> 01:15:52,600
It’s where work becomes accountable.
1610
01:15:52,600 –> 01:15:56,600
It’s where you can see why a decision happened without decompiling a service.
1611
01:15:56,600 –> 01:15:58,640
So the mandate doesn’t reduce power platform.
1612
01:15:58,640 –> 01:16:01,040
It rescues it from being forced to do execution work.
1613
01:16:01,040 –> 01:16:02,280
It was never built to do.
1614
01:16:02,280 –> 01:16:04,200
It’s also not pro-developer elitism.
1615
01:16:04,200 –> 01:16:07,760
This isn’t about real developers versus citizen developers.
1616
01:16:07,760 –> 01:16:11,360
That’s a childish framing, and it’s usually deployed by people who benefit from keeping the
1617
01:16:11,360 –> 01:16:12,520
boundary blurry.
1618
01:16:12,520 –> 01:16:16,840
The enterprise needs both skill sets because the enterprise has both kinds of work, human
1619
01:16:16,840 –> 01:16:19,040
process and deterministic compute.
1620
01:16:19,040 –> 01:16:24,280
The mandate simply assigns those responsibilities to the tiers that can carry them without collapsing.
1621
01:16:24,280 –> 01:16:28,720
Orchestration stays in low code where it’s observable and editable by the business.
1622
01:16:28,720 –> 01:16:31,560
Execution moves to Python where it’s testable and repeatable.
1623
01:16:31,560 –> 01:16:36,080
And governance sits in a zoo where identity, network, policy and logging can be enforced
1624
01:16:36,080 –> 01:16:37,400
by design.
1625
01:16:37,400 –> 01:16:39,520
And it is not a workaround for bad design.
1626
01:16:39,520 –> 01:16:43,160
A workaround is what happens when someone cannot get the platform to do what it should.
1627
01:16:43,160 –> 01:16:48,000
So they root around controls, file watches, local scripts, service accounts, random endpoints,
1628
01:16:48,000 –> 01:16:50,680
just let it through firewall rules.
1629
01:16:50,680 –> 01:16:52,360
The hybrid mandate does the opposite.
1630
01:16:52,360 –> 01:16:57,080
It builds the supported, auditable path on purpose so people stop inventing shadow paths.
1631
01:16:57,080 –> 01:17:00,320
That distinction matters because enterprises always enter hybrid.
1632
01:17:00,320 –> 01:17:04,160
The only question is whether they do it intentionally or whether they do it accidentally
1633
01:17:04,160 –> 01:17:05,160
in the dark.
1634
01:17:05,160 –> 01:17:06,160
Now, what is it?
1635
01:17:06,160 –> 01:17:10,360
It is a maturity model for enterprises that want both agility and engineering discipline.
1636
01:17:10,360 –> 01:17:13,680
At low maturity, everything lives in the orchestration tier.
1637
01:17:13,680 –> 01:17:17,560
Flows become pipelines, connectors become integration strategy, and run history becomes
1638
01:17:17,560 –> 01:17:19,200
the primary debugging tool.
1639
01:17:19,200 –> 01:17:20,880
It works until it doesn’t.
1640
01:17:20,880 –> 01:17:25,000
Then every exception becomes permanent and you’ve converted low code speed into long term
1641
01:17:25,000 –> 01:17:26,080
governance debt.
1642
01:17:26,080 –> 01:17:30,640
At the next maturity level, the organization introduces the execution tier intentionally.
1643
01:17:30,640 –> 01:17:32,800
Python becomes a service, not a sidecar.
1644
01:17:32,800 –> 01:17:34,320
Compute moves out of flows.
1645
01:17:34,320 –> 01:17:35,320
Contracts become explicit.
1646
01:17:35,320 –> 01:17:36,320
Edympotency exists.
1647
01:17:36,320 –> 01:17:37,320
Versioning exists.
1648
01:17:37,320 –> 01:17:38,720
Payloads are bounded.
1649
01:17:38,720 –> 01:17:42,440
Makeers stop writing brittle, passing logic and start consuming stable outputs.
1650
01:17:42,440 –> 01:17:46,360
At the mature level, the governance tier hardens the boundaries so the model survives
1651
01:17:46,360 –> 01:17:47,360
pressure.
1652
01:17:47,360 –> 01:17:52,160
Entra workload identity, private endpoints, dataverse behind the platform, APM enforcing
1653
01:17:52,160 –> 01:17:56,240
policy and contracts and correlated logging, so incidents are evidence-based.
1654
01:17:56,240 –> 01:17:57,240
That’s not bureaucracy.
1655
01:17:57,240 –> 01:18:00,080
That’s how systems stay stable while adoption scales.
1656
01:18:00,080 –> 01:18:03,040
So the hybrid mandate is an enterprise contract, not a diagram.
1657
01:18:03,040 –> 01:18:05,000
Power platform is the orchestration tier.
1658
01:18:05,000 –> 01:18:06,480
Python is the execution tier.
1659
01:18:06,480 –> 01:18:09,680
Azure is the governance tier and the point is not to make things harder.
1660
01:18:09,680 –> 01:18:11,520
The point is to make success survivable.
1661
01:18:11,520 –> 01:18:14,400
This is also the executive instruction stated plainly.
1662
01:18:14,400 –> 01:18:17,240
Mandate boundaries, fund the governance tier and measure drift.
1663
01:18:17,240 –> 01:18:20,240
Because drift is what kills you, not the first deployment.
1664
01:18:20,240 –> 01:18:21,240
Drift.
1665
01:18:21,240 –> 01:18:25,960
The slow accumulation of exceptions, personal connections, public endpoints, unversioned
1666
01:18:25,960 –> 01:18:30,720
APIs and temporary bypasses that quietly become the real architecture.
1667
01:18:30,720 –> 01:18:34,840
If leadership wants a platform that scales without becoming conditional chaos, then leadership
1668
01:18:34,840 –> 01:18:37,960
has to stop rewarding outcomes that ignore boundaries.
1669
01:18:37,960 –> 01:18:41,000
Don’t reward we shipped it if it shipped through a backdoor identity.
1670
01:18:41,000 –> 01:18:45,080
Don’t reward we automated it if it exposed dataverse directly.
1671
01:18:45,080 –> 01:18:50,440
Don’t reward we added AI if nobody can explain the prompt, the version, the cost or the
1672
01:18:50,440 –> 01:18:51,720
audit story.
1673
01:18:51,720 –> 01:18:55,920
Reward the pattern, reward the contract, reward the evidence.
1674
01:18:55,920 –> 01:19:01,200
That’s what maturity looks like the organization can move fast and still prove it stayed in control.
1675
01:19:01,200 –> 01:19:05,400
The only takeaway that matter, the only takeaway that matters is this.
1676
01:19:05,400 –> 01:19:10,720
Keep orchestration in power platform, put deterministic compute in Python and enforce the boundaries
1677
01:19:10,720 –> 01:19:14,360
in Azure or the system degrades into conditional chaos.
1678
01:19:14,360 –> 01:19:19,400
If you want, I can do a follow-up episode that maps this to a concrete reference architecture,
1679
01:19:19,400 –> 01:19:24,600
enter a workload identity, APIM policies, private endpoints, correlation IDs and the minimum
1680
01:19:24,600 –> 01:19:26,880
viable contracts that stop drift.
1681
01:19:26,880 –> 01:19:30,720
Subscribe for that and send me the hybrid pattern that’s failing in your tenant right now,
1682
01:19:30,720 –> 01:19:33,320
what boundary collapsed and what exception became normal.






