Standard scope
Applies to: All HCS-governed repositories that package a deployable solution — infrastructure, workload, or operational tooling — for one or more use cases Domain: solutions Status: Active
Solutions standard
This standard was consolidated from two independently-evolved standards — the AzureLocal platform's solutions.md and TierPoint ProdTech's Solution Development Standard — that converged on nearly identical rules for how a solution is packaged, kept in sync across automation toolchains, and documented. Because the two source standards agreed on ~90% of their content, this is a single base standard with no scope overlay: it applies the same way to every HCS-governed project.
What qualifies as a solution
A solution is a deployable package that provisions and/or configures infrastructure, a workload, or an operational capability for a specific, named use case. Examples include a Scale-Out File Server (SOFS) deployment for FSLogix, an Azure Virtual Desktop (AVD) session host pool, an AKS cluster on Azure Local, or a load-testing toolkit.
A solution is defined by three things:
- A single, named directory — every solution lives in its own directory (for example
solutions/<solution-name>/), never spread across unrelated locations in the repository. - A mapped infrastructure type — every solution maps to an infrastructure type entry in the project's master variable registry (see the variables and naming standard). The infrastructure type is what ties the solution's configuration to the shared variable chain described below.
- A declared set of supported automation tools — the tools a user can choose from to deploy and configure the solution (PowerShell, Terraform, Bicep, ARM, Ansible, or any combination).
Non-IaC solutions
Some solutions are operational or diagnostic tools rather than infrastructure-as-code (IaC) deployment packages — for example a load-testing toolkit or an AI-assisted operations tool. These follow the same repository and documentation rules in this standard, but the multi-tool parity and parameter-derivation rules below do not apply, because there is no infrastructure to keep in parity across tools. Document the exception in the solution's own README.md.
Solution directory structure
Every solution directory follows a consistent internal layout so that engineers moving between solutions do not have to relearn the structure each time:
solutions/<solution-name>/
├── solution-<name>.yml # Generated solution config — derived from the master variable registry, never hand-edited
├── README.md # Solution overview, prerequisites, quick-start
├── powershell/ # PowerShell automation (present if PowerShell is a supported tool)
├── terraform/ # Terraform automation (present if Terraform is a supported tool)
├── bicep/ # Bicep templates (present if Bicep is a supported tool)
└── arm/ # ARM templates (present if ARM is a supported tool)Only include the subdirectories for tools the solution actually supports — do not create empty placeholder directories for tools that are not implemented.
Generated config is read-only
The per-solution config file (solution-<name>.yml or equivalent) is generated from the project's master variable registry and environment configuration. Never hand-edit it. If a value is wrong, fix it at the source (the master registry or the environment-specific configuration file) and regenerate the solution config.
The multi-tool parity requirement
If a solution supports more than one automation toolchain — any combination of PowerShell, Terraform, Bicep, ARM, or Ansible — those toolchains must produce equivalent infrastructure.
Every automation tool provided for a solution must produce the same infrastructure outcome. A user switching from Terraform to PowerShell, or from Bicep to Ansible, for the same solution must get an identical deployment.
Parity means, at minimum, that every supported tool:
- Creates the same resources, using the same configuration values
- Reads its input from the same source of truth (see single source of truth, below) — never from tool-specific values that bypass the shared configuration chain
- Supports the same features — for example, if one tool supports per-instance storage paths or static IP assignment, every other supported tool for that solution must support it too
- Produces equivalent outputs — resource IDs, connection strings, and any other value downstream automation depends on
Each tool declares which phases of a deployment it covers — provisioning Azure resources, configuring the guest operating system, networking, and monitoring. A tool that provisions Azure resources but does not configure the guest OS (most IaC tools) delegates OS configuration to a companion tool such as PowerShell or Ansible; this is expected and does not violate parity, as long as the delegation is documented and the companion tool is one of the solution's declared supported tools.
| Deployment phase | What it covers |
|---|---|
| Azure resources | Provisioning cloud or hybrid infrastructure objects |
| Configuration | Guest OS setup, role installation, domain join |
| Networking | Virtual networks, subnets, NICs, IP assignment |
| Monitoring | Diagnostics, alerting, log forwarding |
How changes propagate across toolchain variants
Sync-on-change is mandatory
Mandatory
When a feature, variable, or configuration change is made to any automation tool for a solution, every other automation tool that solution supports must be updated in the same commit or pull request. A change that updates Terraform but not the equivalent Bicep template is an incomplete change, not a follow-up task.
The table below shows what must be touched for each type of change:
| Change type | What must be updated |
|---|---|
| New variable added | Master variable registry → environment configuration → solution config → every supported automation tool |
| Variable value changed | Environment configuration → regenerated solution config → verify every tool reads the new value |
| New resource added | Every supported automation tool must create the resource with identical configuration |
| Resource property changed | Every supported automation tool must reflect the change |
| Feature added (for example, per-instance storage paths) | Every supported automation tool must implement the feature |
Parity review checklist
Every pull request or merge request that modifies a solution must include a parity checklist in its description. Adapt the tool list to the solution's declared supported tools:
## Solution parity checklist
- [ ] PowerShell scripts updated and tested
- [ ] Terraform configuration updated and `terraform plan` output is clean
- [ ] Bicep templates updated (if applicable)
- [ ] ARM templates updated (if applicable)
- [ ] Master variable registry updated (if new variables were introduced)
- [ ] Environment configuration updated
- [ ] Solution config regenerated
- [ ] All supported tools produce equivalent dry-run output (`--what-if`, `-WhatIf`, or `plan`)A reviewer should reject a pull request that modifies solution automation without a completed parity checklist.
Verifying parity before merge
Before merging any solution change, run every supported tool's dry-run mode and confirm the output reports the same set of resources and configuration values:
# PowerShell
.\solutions\<solution-name>\powershell\Deploy-<Name>-Azure.ps1 -WhatIf# Terraform
terraform plan -var-file="terraform.tfvars"# Bicep
az deployment group what-if --template-file main.bicep --parameters @parameters.jsonSingle source of truth
Every tool-specific parameter file a solution ships (a Terraform .tfvars file, a Bicep parameters file, an ARM parameters file, an Ansible inventory) is a derived, convenience copy of the solution's central configuration. It must be possible to regenerate every one of these files from the master variable registry and the environment-specific configuration.
The configuration chain is non-negotiable and flows in one direction only:
Master variable registry ← Variable definitions: type, validation, description
↓
Environment configuration ← Environment-specific values (dev, stg, prd)
↓
Solution mapping ← Which variables this solution requires
↓
Generated solution config ← What scripts and templates actually consume (read-only)Rules that apply to every solution, regardless of which tools it supports:
- Scripts and templates read from the generated solution config — never directly from the environment configuration file
- If a tool-specific parameter file's values drift from the environment configuration, the environment configuration wins; regenerate the parameter file
- No automation tool may define its own variables that bypass this chain
- Every reference to a configuration value in a script should carry an inline comment identifying the configuration path it came from, so the source is traceable without cross-referencing another file
Variable governance
Every variable a solution uses must exist in three places before it can be used:
- The master variable registry, with a type, description, and validation rule
- The environment-specific configuration file, with the environment's actual value
- The solution's variable mapping, listing it as required (or optional) for that solution
A variable that appears in a tool-specific file (a .tfvars file, a PowerShell script) but not in the master registry is an orphan variable and must be registered before the change is merged. See the variables and naming standard for the naming pattern, validation rules, and the keyvault:// URI scheme used for secret-backed values.
When a configuration property varies per resource instance — for example, a distinct storage path for each of several virtual machines in a solution — use a map-typed variable, and have scripts iterate the map by key rather than hardcoding per-instance values.
Documentation requirements for a solution
Every solution must ship documentation covering:
| Document | Purpose |
|---|---|
| Solution overview | Architecture, prerequisites, and the design decisions behind the solution |
| Deployment guide | Step-by-step instructions for deploying the solution with each supported tool |
| Variable reference | Every solution-specific variable, with its description and source |
| Troubleshooting | Common failure modes and how to recover from them |
A deployment guide that walks an engineer through provisioning or configuring infrastructure with more than one execution method — a portal, a script run from a management host, or a fully self-contained script — should follow the provisioning standard for how to structure and present those execution options.
Every solution must also have a README.md that meets the baseline requirements in the documentation standard, and must not skip the required-files check that standard defines for every repository.
Related standards
- Variables and naming standard — master registry,
keyvault://URI scheme, and the naming rules solution variables must follow - Infrastructure standard — IaC tool selection and the four deployment phases (Plan, Provision, Configure, Validate)
- Scripting standard — PowerShell conventions, credential resolution, and logging that solution scripts must follow
- Provisioning standard — documenting multi-execution-path deployment guides for a solution
- Documentation standard — baseline documentation requirements every repository, including every solution, must meet