lab-shared-contract

star 2

Single source of truth for cross-cutting rules referenced by all agents and skills in the lab pipeline. Every requirement has a unique ID (R-0xx).

Greg-T8 By Greg-T8 schedule Updated 3/19/2026

name: lab-shared-contract description: Single source of truth for cross-cutting rules referenced by all agents and skills in the lab pipeline. Every requirement has a unique ID (R-0xx).

Shared Contract

Authoritative cross-cutting rules for the hands-on lab pipeline. Every requirement is identified by a unique ID (R-0xx). Other files MUST reference these IDs — never restate the rule.

For the full Azure governance implementation policy, see Governance-Lab.md at .assets/shared/Governance-Lab.md.


R-001: Resource Group Naming

Pattern: <exam>-<domain>-<topic>-<deployment>

  • <exam>: lowercase exam code (az104, az305)
  • <domain>: lowercase domain slug (e.g., networking, storage, generative-ai)
  • <topic>: lowercase topic slug (e.g., vnet-peering, blob-versioning)
  • <deployment>: tf | bicep | scripted

Example: az104-networking-vnet-peering-tf


R-002: Resource Naming — AZ-104 Prefixes

Pattern: <prefix>-<role>[-instance]

  • <role> describes the resource's function in the lab scenario — NOT the lab topic (see R-031).

All names are static by default. Random suffixes are only added for resources subject to soft-delete retention (see R-028).

Resource Prefix Random Suffix?
VNet vnet No
Subnet snet No
NSG nsg No
VM vm No
Storage st<exam><role> (no hyphens) No
Load Balancer lb No
Key Vault kv R-028
Log Analytics law No
Recovery Vault rsv R-028

R-003: Resource Naming — AI-103 Prefixes

Pattern: <prefix>-<role>[-instance]

  • <role> describes the resource's function in the lab scenario — NOT the lab topic (see R-031).

All names are static by default. Random suffixes are only added for resources subject to soft-delete retention (see R-028).

Resource Prefix Random Suffix?
OpenAI oai R-028
Multi-service cog R-028
Vision cv R-028
Language lang R-028
AI Search srch No
Deployment deploy No
Cosmos DB cosmos No
Storage (AI output) st<exam><role> No

Cognitive Services resources (OpenAI, Multi-service, Vision, Language) require random suffix because they enter soft-deleted state on deletion — see R-028.

These prefixes apply to AI-103 labs. Legacy AI-102 artifacts also follow these conventions.


R-004: Bicep Stack Naming

Pattern: stack-<domain>-<topic>

No exam code in stack name.


R-005: Required Tags (All Resources)

Tag Rule
Environment Always Lab
Project Uppercase: AZ-104, AZ-305, or AI-103
Domain e.g., Networking, Storage, Generative AI
Purpose Descriptive (e.g., VNet Peering)
Owner Greg Tate
DateCreated Static YYYY-MM-DD — no timestamp() / utcNow()
DeploymentMethod Terraform or Bicep

R-006: Region Rules

Setting Value
Default eastus
Fallback westus2eastus2centralus
Allowed Any US region

Use eastus unless capacity requires fallback.


R-007: Infrastructure SKU Defaults

Resource Default
VM Standard_B2s (B1s if sufficient)
Storage Standard LRS
Load Balancer Basic
Public IP Basic
SQL Basic / S0
Disk Standard HDD

R-008: AI Service SKU Defaults

Service Default
OpenAI S0
Cognitive Services F0 → S0
Computer Vision F0
Custom Vision F0
Language F0
Translator F0
Speech F0
Form Recognizer F0
AI Search Free / Basic

Start free tier when available.


R-009: Per-Lab Resource Limits

Resource Max
VMs 4
Public IPs 5
Storage Accounts 3
VNets 4
OpenAI Accounts 2
Cognitive Accounts 3
Model Deployments 4

R-010: Lab Folder Structure

IaaC (Terraform)

<EXAM>/hands-on-labs/<domain>/lab-<topic>/
├── README.md
├── terraform/
│   ├── main.tf
│   ├── variables.tf
│   ├── outputs.tf
│   ├── providers.tf
│   ├── terraform.tfvars
│   └── modules/
│       └── <module>/
│           ├── main.tf
│           ├── variables.tf
│           └── outputs.tf
└── validation/
    └── <validation-script>.ps1

IaaC (Bicep)

<EXAM>/hands-on-labs/<domain>/lab-<topic>/
├── README.md
├── bicep/
│   ├── main.bicep
│   ├── main.bicepparam
│   ├── bicepconfig.json
│   ├── bicep.ps1
│   └── modules/
│       └── <module>.bicep
└── validation/
    └── <validation-script>.ps1

Scripted

<EXAM>/hands-on-labs/<domain>/lab-<topic>/
├── README.md
├── scripts/
│   ├── deploy.*
│   ├── config.* (if needed)
│   └── cleanup.*
└── validation/

Manual

<EXAM>/hands-on-labs/<domain>/lab-<topic>/
├── README.md
└── screenshots/ (optional)

R-011: README 14-Section Order

Every lab README must contain these sections in this exact sequence:

  1. Exam Question Scenario / Exam Task (depends on Intake Mode)
  2. Solution Architecture
  3. Architecture Diagram
  4. Lab Objectives
  5. Lab Structure
  6. Prerequisites
  7. Deployment
  8. Testing the Solution
  9. Cleanup
  10. Scenario Analysis / Task Deep Dive (depends on Intake Mode)
  11. Key Learning Points
  12. Related Objectives
  13. Additional Resources
  14. Related Labs

R-012: Code Header Block

Include in all .tf, .bicep, .ps1 files. Do NOT include in README.

# -------------------------------------------------------------------------
# Program: [filename]
# Description: [purpose]
# Context: [EXAM] Lab - [scenario]
# Author: Greg Tate
# Date: [YYYY-MM-DD]
# -------------------------------------------------------------------------

Use // for .bicep files, # for .tf and .ps1.


R-013: Mermaid Diagram Criteria

  • Always required — every lab README must include a Mermaid diagram
  • When 2+ interconnected resources are deployed, diagram the resource topology (dependencies, network paths, data flow)
  • When fewer than 2 interconnected resources, diagram the overall process reflective of the exam question (e.g., data flow from source → service → output, access methods, decision paths)
  • Use graph TD (top-down) for hierarchical layouts or graph LR (left-right) for pipeline / process flows
  • Resource names must match governance naming conventions
  • Show dependencies and relationships

R-014: Review Report Schema

## Review Summary
- Overall: [PASS | FAIL]
- Checks Passed: [X/Y]
- Critical Violations: [count]

## Detailed Results

### [Category Name]
- [Check]: PASS
- [Check]: FAIL — [issue and fix]

## Required Fixes (if FAIL)
1. [File]: [exact change]

R-015: Cleanup Policy

  • Destroy lab resources within 7 days
  • Track via DateCreated tag
  • README cleanup section must reference 7-day policy
  • Reference labs must justify permanence in README

R-016: Soft-Delete / Purge

Resources Requiring Purge

Resource Retention Manual Purge Requires Random Suffix (R-028)
Cognitive Services 48 hrs Yes Yes — name reserved during retention
Key Vault 7–90 days Yes Yes — name reserved during retention
API Management 48 hrs Yes Yes — name reserved during retention
Recovery Vault 14 days Yes Yes — backup items block name reuse
App Insights 14 days No No — soft-delete can be disabled
Log Analytics 14 days No No — soft-delete can be disabled

Only resources whose names are reserved during soft-delete retention require random suffixes (see R-028). All other resources use static names.

Disable Patterns

Terraform:

soft_delete_enabled                          = false
purge_soft_delete_on_destroy                 = false   # Unique names eliminate need to purge; false speeds up destroy
permanently_delete_on_destroy                = true    # Log Analytics
purge_protected_items_from_vault_on_destroy  = true    # Recovery Vault

Bicep:

softDeleteState: 'Disabled'

R-017: Deployment Method Priority

IaaC > Scripted > Manual

Method Use When
IaaC (Terraform / Bicep) Deploying Azure resources, architecture focus, repeatable
Scripted (PowerShell/CLI) Imperative workflows, operational focus
Manual (Portal / UI) Portal navigation is tested, UI-centric

If IaaC, always ask user to choose Terraform or Bicep. Never auto-select.


R-018: IaaC Validation Sequence

  1. Validate Syntax — terraform validate or bicep build
  2. Regional Capacity Test — for constrained services (see R-019)
  3. Final Validation — terraform plan or deployment preview

Terraform:

Use-AzProfile Lab
Test-Path terraform.tfvars
terraform init
terraform validate
terraform fmt
# Capacity tests here (R-019)
terraform plan

Bicep:

Use-AzProfile Lab
.\bicep.ps1 validate
# Capacity tests here (R-019)
.\bicep.ps1 plan

R-019: Capacity-Constrained Services

Services requiring regional capacity validation before deployment:

  • Cosmos DB (Microsoft.DocumentDB)
  • AI Search (Microsoft.Search)
  • OpenAI / Cognitive Services (Microsoft.CognitiveServices)

Validation commands:

az provider show --namespace Microsoft.DocumentDB `
    --query "resourceTypes[?resourceType=='databaseAccounts'].locations[]"

az provider show --namespace Microsoft.Search `
    --query "resourceTypes[?resourceType=='searchServices'].locations[]"

az provider show --namespace Microsoft.CognitiveServices `
    --query "resourceTypes[?resourceType=='accounts'].locations[]"

If unavailable, use fallback regions per R-006.


R-020: Lab Subscription

e091f6e7-031a-4924-97bb-8c983ca5d21a

Must appear in:

  • terraform.tfvarslab_subscription_id
  • Bicep → subscription context validation
  • Validation scripts → subscription check

R-021: Language Style Conventions

Tool Style
Terraform snake_case
Bicep camelCase params
Azure Names Prefix standards per R-002 / R-003

R-022: Module Rule

Use modules when 2+ related resource types are deployed.

  • Domain grouping (one concern per module)
  • Self-contained with clear inputs/outputs
  • Pass common_tags (TF) / commonTags (Bicep) to all modules
  • Pass identity references (e.g., principal_id) as explicit inputs for RBAC
  • Thin orchestration in root main.tf / main.bicep
  • Anti-pattern: consolidating unrelated resource types into a single module

R-023: Common Tags Variable Pattern

Terraform:

locals {
  common_tags = {
    Environment      = "Lab"
    Project          = "<EXAM>"
    Domain           = "<Domain>"
    Purpose          = "<Purpose>"
    Owner            = var.owner
    DateCreated      = var.date_created
    DeploymentMethod = "Terraform"
  }
}

Bicep:

var commonTags = {
  Environment: 'Lab'
  Project: '<EXAM>'
  Domain: '<Domain>'
  Purpose: '<Purpose>'
  Owner: owner
  DateCreated: dateCreated
  DeploymentMethod: 'Bicep'
}

R-024: Password Generation

Must meet Azure complexity. Mark as @secure() (Bicep) or sensitive (Terraform). May be specified in a parameters file.

Terraform: Use hashicorp/random or supply via terraform.tfvars.

resource "random_password" "admin" {
  length           = 16
  special          = true
  override_special = "!@#$%"
}

Bicep: Use uniqueString(), static pattern, or supply in .bicepparam. Mark @secure().

Target pattern: AzureLab2026!


R-025: Azure Configuration Guardrails

  • Load Balancer SNAT: Set disableOutboundSnat = true when frontend used for inbound + outbound
  • NIC + Public IP: NIC with instance public IP cannot join outbound backend pool
  • Storage Containers (TF): Use storage_account_id not storage_account_name
  • AI Services: Enable public network access for labs; validate model availability per region; start minimal capacity; output keys as sensitive
  • AI Agent RBAC: Requires both data plane + control plane roles (e.g., Cosmos DB Operator)

For full details, see Governance-Lab.md at .assets/shared/Governance-Lab.md.


R-026: Bastion Dependency Ordering (Required)

Azure Bastion Developer SKU requires the VNet to be in Succeeded state. Creating Bastion in parallel with subnet resources causes a BastionHostVirtualNetworkNotFound race condition.

Always declare an explicit dependency so Bastion creation waits for all networking resources to complete.

Terraform — add depends_on to the module that contains azurerm_bastion_host:

module "compute" {
  # ...
  depends_on = [module.networking]
}

Bicep — add dependsOn to the Bastion resource or module:

resource bastion 'Microsoft.Network/bastionHosts@2024-10-01' = {
  name: bastionName
  // ...
  dependsOn: [
    networkingModule
  ]
}

R-027: Static Names by Default

All resource names must be static and predictable unless the resource is subject to soft-delete name reservation (see R-028).

  • Static name: A literal string with no runtime-generated components (uniqueString(), random_string, etc.).
  • Storage accounts, VMs, VNets, NSGs, subnets, load balancers, and all other non-soft-delete resources use static names.
  • This keeps README code blocks, architecture diagrams, and testing steps simple and reproducible.

R-028: Random Suffix — Soft-Delete Resources Only

Random suffixes are only permitted for resources that enter a soft-deleted state where the name is reserved during the retention period. These are listed in R-016.

Resources Requiring Random Suffix

Resource Reason
Cognitive Services Name reserved 48 hrs after deletion
Key Vault Name reserved 7–90 days after deletion
API Management Name reserved 48 hrs after deletion
Recovery Vault Backup items block immediate name reuse

Random Suffix Format

Bicep: '${resourcePrefix}${topic}${uniqueString(resourceGroup().id)}'

Terraform: "${resourcePrefix}-${topic}-${random_string.suffix.result}"

Length: 4 lowercase alphanumeric characters.

Resources That Do NOT Get Random Suffix

Even if globally unique (e.g., storage accounts), these resources do not need random suffixes because their names are released immediately on deletion:

  • Storage Accounts
  • AI Search
  • Cosmos DB
  • Log Analytics (soft-delete can be disabled)
  • App Insights (soft-delete can be disabled)

R-029: README-to-IaC Resource Name Consistency

All resource names referenced in the README must exactly match the names defined in the IaC code. The README (authored in Phase 2) establishes the intended names. The IaC code (generated in Phase 3) must implement those same names.

This applies to all resource types: resource groups, VMs, storage accounts, VNets, NSGs, Key Vaults, and any other named Azure resource.

Scope

README Section What to Check
Architecture Diagram Node labels and resource name annotations
Deployment Resource group name, stack name, all -Name values
Testing the Solution All -Name, -ResourceGroupName, and -StorageAccountId references
Cleanup Resource group names, purge targets
Scenario Analysis Code snippets referencing deployed resources

Enforcement

  • The Lab-Reviewer (Phase 4) must cross-reference every resource name in the README against the corresponding name in the IaC code.
  • Any mismatch — in either direction — is a Category 1 Naming Compliance FAIL.
  • The fix must align the IaC name to the README, or update the README to reflect the actual IaC name, before delivery.
  • If the IaC uses a random suffix for a resource that should have a static name per R-027/R-028, flag it as a Naming Compliance FAIL.

R-030: Command-Line Fidelity

All command-line snippets in README Testing the Solution, Deployment, and Validation sections must be syntactically correct and produce the stated expected output when run against the deployed resources.

What to Check

Check Description
Property names Cmdlet output properties must match the actual object model (e.g., AccountName not Name for Get-AzCognitiveServicesAccount; StorageAccountName not Name for Get-AzStorageAccount)
Nested properties Properties that return complex objects must be expanded to show the intended value (e.g., $account.Sku.Name not $account.Sku when the expected output is a SKU tier string)
Format expressions Format-List / Format-Table expressions must reference properties that exist on the object; use calculated properties (@{n=...;e=...}) when expanding nested values
Cmdlet parameters All -ParameterName values must be valid for the cmdlet being invoked
Variable references Variables set in earlier steps must be reachable in later steps within the same README section
Expected output comments # Expected: comments must match what the command actually returns
API versions REST API api-version values must be current and valid for the service
Pipeline correctness Piped commands must accept the preceding output type

Enforcement

  • The Lab-Reviewer (Phase 4) evaluates command-line fidelity as Category 11.
  • A FAIL in Category 11 does not block delivery on its own, but each issue must include an actionable fix.
  • Common violations: wrong property names, unexpanded nested objects, stale API versions, invalid parameter names.

R-031: Role-Based Resource Names (No Topic Echo)

Resource names must describe the resource's role or function in the lab scenario — never echo the lab topic.

Why

When every resource is named <prefix>-<topic>, the names imply each resource IS the concept being studied rather than a resource that DEMONSTRATES the concept. This creates confusion, especially for resources that configure or contain the feature under study.

Rule

  • The resource group retains the topic-based name per R-001 (e.g., az104-compute-keda-scaling-rule-bicep).
  • Individual resources within the lab use scenario-appropriate role names that describe what the resource does.
  • Each resource should have a distinct, practical name — avoid giving every resource the same suffix.

Examples

Lab: lab-keda-scaling-rule (Container App with KEDA scaling)

Resource Type Bad (topic echo) Good (role-based)
Container App ca-keda-scaling-rule ca-order-processor
Container Apps Environment cae-keda-scaling-rule cae-lab
Service Bus Namespace sbns-keda-scaling-rule sbns-orders
Log Analytics Workspace law-keda-scaling-rule law-monitoring

Lab: lab-vnet-peering (Two peered VNets)

Resource Type Bad (topic echo) Good (role-based)
VNet vnet-vnet-peering-1 vnet-hub
VNet vnet-vnet-peering-2 vnet-spoke
NSG nsg-vnet-peering nsg-web-tier

Lab: lab-blob-versioning (Storage with versioning enabled)

Resource Type Bad (topic echo) Good (role-based)
Storage Account staz104blobversioning staz104documents
Log Analytics law-blob-versioning law-monitoring

Choosing Good Role Names

  • Ask: "What does this resource represent in the scenario?" — not "What concept does this lab teach?"
  • Draw names from the workload domain: orders, web-frontend, monitoring, hub, spoke, documents, media, inventory.
  • Supporting infrastructure can use generic role names: law-monitoring, cae-lab, nsg-default.
  • Keep names short (1–2 words after the prefix).
Install via CLI
npx skills add https://github.com/Greg-T8/LearningAzure --skill lab-shared-contract
Repository Details
star Stars 2
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator