The Hybrid Mandate: Python in Power Platform

Mirko PetersPodcasts2 hours ago20 Views


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.





Source link

0 Votes: 0 Upvotes, 0 Downvotes (0 Points)

Leave a reply

Follow
Search
Popular Now
Loading

Signing-in 3 seconds...

Signing-up 3 seconds...

Discover more from 365 Community Online

Subscribe now to keep reading and get access to the full archive.

Continue reading